Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft EdgeMore info about Internet Explorer and Microsoft Edge
Table of contentsExit editor mode

ASP.NET Core Razor components

Feedback

In this article

Note

This isn't the latest version of this article. For the current release, see the.NET 10 version of this article.

Warning

This version of ASP.NET Core is no longer supported. For more information, see the.NET and .NET Core Support Policy. For the current release, see the.NET 9 version of this article.

This article explains how to create and use Razor components in Blazor apps, including guidance on Razor syntax, component naming, namespaces, and component parameters.

Razor components

Blazor apps are built usingRazor components, informally known asBlazor components or onlycomponents. A component is a self-contained portion of user interface (UI) with processing logic to enable dynamic behavior. Components can be nested, reused, shared among projects, and used in MVC and Razor Pages apps.

Components render into an in-memory representation of the browser'sDocument Object Model (DOM) called arender tree, which is used to update the UI in a flexible and efficient way.

Although "Razor components" shares some naming with other ASP.NET Core content-rendering technologies, Razor components must be distinguished from the following different features in ASP.NET Core:

Important

When using a Blazor Web App, most of the Blazor documentation example componentsrequire interactivity to function and demonstrate the concepts covered by the articles.Interactivity makes it possible for users to interact with rendered components. This includes app responses toDocument Object Model (DOM) events and state changes tied to C# members via Blazor's event handlers and binding. When you test an example component provided by an article in a Blazor Web App, make sure that either the app adopts global interactivity or the component adopts an interactive render mode. More information on this subject is provided byASP.NET Core Blazor render modes, which is the next article in the table of contents after this article.

Component classes

Components are implemented using a combination of C# and HTML markup inRazor component files with the.razor file extension.

ComponentBase is the base class for components described by Razor component files.ComponentBase implements the lowest abstraction of components, theIComponent interface.ComponentBase defines component properties and methods for basic functionality, for example, to process a set of built-in component lifecycle events.

ComponentBase indotnet/aspnetcore reference source: The reference source contains additional remarks on the built-in lifecycle events. However, keep in mind that the internal implementations of component features are subject to change at any time without notice.

Note

Documentation links to .NET reference source usually load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use theSwitch branches or tags dropdown list. For more information, seeHow to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).

Developers typically create Razor components from Razor component files (.razor) or base their components onComponentBase, but components can also be built by implementingIComponent. Developer-built components that implementIComponent can take low-level control over rendering at the cost of having to manually trigger rendering with events and lifecycle methods that the developer must create and maintain.

Additional conventions adopted by Blazor documentation example code and sample apps is found inASP.NET Core Blazor fundamentals.

Razor syntax

Components useRazor syntax. Two Razor features are extensively used by components,directives anddirective attributes. These are reserved keywords prefixed with@ that appear in Razor markup:

  • Directives: Change the way component markup is compiled or functions. For example, the@page directive specifies a routable component with a route template that can be reached directly by a user's request in the browser at a specific URL.

    By convention, a component's directives at the top of a component definition (.razor file) are placed in a consistent order. For repeated directives, directives are placed alphabetically by namespace or type, except@using directives, which have special second-level ordering.

    The following order is adopted by Blazor sample apps and documentation. Components provided by a Blazor project template may differ from the following order and use a different format. For example, Blazor framework Identity components include blank lines between blocks of@using directives and blocks of@inject directives. You're free to use a custom ordering scheme and format in your own apps.

    Documentation and sample app Razor directive order:

    • @page
    • @rendermode (.NET 8 or later)
    • @using
      • System namespaces (alphabetical order)
      • Microsoft namespaces (alphabetical order)
      • Third-party API namespaces (alphabetical order)
      • App namespaces (alphabetical order)
    • Other directives (alphabetical order)

    Note

    Arender mode is only applied in Blazor Web Apps and includes modes that establish user interactivity with the rendered component. For more information, seeASP.NET Core Blazor render modes.

    No blank lines appear among the directives. One blank line appears between the directives and the first line of Razor markup.

    Example:

    @page "/doctor-who-episodes/{season:int}"@rendermode InteractiveWebAssembly@using System.Globalization@using System.Text.Json@using Microsoft.AspNetCore.Localization@using Mandrill@using BlazorSample.Components.Layout@attribute [Authorize]@implements IAsyncDisposable@inject IJSRuntime JS@inject ILogger<DoctorWhoEpisodes> Logger<PageTitle>Doctor Who Episode List</PageTitle>...
  • Directive attributes: Change the way a component element is compiled or functions.

    Example:

    <input @bind="episodeId" />

    You can prefix directive attribute values with the at symbol (@) for non-explicit Razor expressions (@bind="@episodeId"), but we don't recommend it, and the docs don't adopt the approach in examples.

Directives and directive attributes used in components are explained further in this article and other articles of the Blazor documentation set. For general information on Razor syntax, seeRazor syntax reference for ASP.NET Core.

Component name, class name, and namespace

A component's name must start with an uppercase character:

Supported:ProductDetail.razor

Unsupported:productDetail.razor

Common Blazor naming conventions used throughout the Blazor documentation include:

  • File paths and file names use Pascal case† and appear before showing code examples. If a path is present, it indicates the typical folder location. For example,Components/Pages/ProductDetail.razor indicates that theProductDetail component has a file name ofProductDetail.razor and resides in thePages folder of theComponents folder of the app.
  • Component file paths for routable components match their URLs in kebab case‡ with hyphens appearing between words in a component's route template. For example, aProductDetail component with a route template of/product-detail (@page "/product-detail") is requested in a browser at the relative URL/product-detail.

†Pascal case (upper camel case) is a naming convention without spaces and punctuation and with the first letter of each word capitalized, including the first word.
‡Kebab case is a naming convention without spaces and punctuation that uses lowercase letters and dashes between words.

Components are ordinaryC# classes and can be placed anywhere within a project. Components that produce webpages usually reside in theComponents/Pages folder. Non-page components are frequently placed in theComponents folder or a custom folder added to the project.

Typically, a component's namespace is derived from the app's root namespace and the component's location (folder) within the app. If the app's root namespace isBlazorSample and theCounter component resides in theComponents/Pages folder:

  • TheCounter component's namespace isBlazorSample.Components.Pages.
  • The fully qualified type name of the component isBlazorSample.Components.Pages.Counter.

For custom folders that hold components, add an@using directive to the parent component or to the app's_Imports.razor file. The following example makes components in theAdminComponents folder available:

@using BlazorSample.AdminComponents

Note

@using directives in the_Imports.razor file are only applied to Razor files (.razor), not C# files (.cs).

Aliasedusing statements are supported. In the following example, the publicWeatherForecast class of theGridRendering component is made available asWeatherForecast in a component elsewhere in the app:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

Components can also be referenced using their fully qualified names, which doesn't require an@using directive. The following example directly references theProductDetail component in theAdminComponents/Pages folder of the app:

<BlazorSample.AdminComponents.Pages.ProductDetail />

The namespace of a component authored with Razor is based on the following (in priority order):

  • The@namespace directive in the Razor file's markup (for example,@namespace BlazorSample.CustomNamespace).
  • The project'sRootNamespace in the project file (for example,<RootNamespace>BlazorSample</RootNamespace>).
  • The project namespace and the path from the project root to the component. For example, the framework resolves{PROJECT NAMESPACE}/Components/Pages/Home.razor with a project namespace ofBlazorSample to the namespaceBlazorSample.Components.Pages for theHome component.{PROJECT NAMESPACE} is the project namespace. Components follow C# name binding rules. For theHome component in this example, the components in scope are all of the components:
    • In the same folder,Components/Pages.
    • The components in the project's root that don't explicitly specify a different namespace.

The following arenot supported:

  • Theglobal:: qualification.
  • Partially-qualified names. For example, you can't add@using BlazorSample.Components to a component and then reference theNavMenu component in the app'sComponents/Layout folder (Components/Layout/NavMenu.razor) with<Layout.NavMenu></Layout.NavMenu>.

A component's name must start with an uppercase character:

Supported:ProductDetail.razor

Unsupported:productDetail.razor

Common Blazor naming conventions used throughout the Blazor documentation include:

  • File paths and file names use Pascal case† and appear before showing code examples. If a path is present, it indicates the typical folder location. For example,Pages/ProductDetail.razor indicates that theProductDetail component has a file name ofProductDetail.razor and resides in thePages folder of the app.
  • Component file paths for routable components match their URLs in kebab case‡ with hyphens appearing between words in a component's route template. For example, aProductDetail component with a route template of/product-detail (@page "/product-detail") is requested in a browser at the relative URL/product-detail.

†Pascal case (upper camel case) is a naming convention without spaces and punctuation and with the first letter of each word capitalized, including the first word.
‡Kebab case is a naming convention without spaces and punctuation that uses lowercase letters and dashes between words.

Components are ordinaryC# classes and can be placed anywhere within a project. Components that produce webpages usually reside in thePages folder. Non-page components are frequently placed in theShared folder or a custom folder added to the project.

Typically, a component's namespace is derived from the app's root namespace and the component's location (folder) within the app. If the app's root namespace isBlazorSample and theCounter component resides in thePages folder:

  • TheCounter component's namespace isBlazorSample.Pages.
  • The fully qualified type name of the component isBlazorSample.Pages.Counter.

For custom folders that hold components, add an@using directive to the parent component or to the app's_Imports.razor file. The following example makes components in theAdminComponents folder available:

@using BlazorSample.AdminComponents

Note

@using directives in the_Imports.razor file are only applied to Razor files (.razor), not C# files (.cs).

Aliasedusing statements are supported. In the following example, the publicWeatherForecast class of theGridRendering component is made available asWeatherForecast in a component elsewhere in the app:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

Components can also be referenced using their fully qualified names, which doesn't require an@using directive. The following example directly references theProductDetail component in theComponents folder of the app:

<BlazorSample.Components.ProductDetail />

The namespace of a component authored with Razor is based on the following (in priority order):

  • The@namespace directive in the Razor file's markup (for example,@namespace BlazorSample.CustomNamespace).
  • The project'sRootNamespace in the project file (for example,<RootNamespace>BlazorSample</RootNamespace>).
  • The project namespace and the path from the project root to the component. For example, the framework resolves{PROJECT NAMESPACE}/Pages/Index.razor with a project namespace ofBlazorSample to the namespaceBlazorSample.Pages for theIndex component.{PROJECT NAMESPACE} is the project namespace. Components follow C# name binding rules. For theIndex component in this example, the components in scope are all of the components:
    • In the same folder,Pages.
    • The components in the project's root that don't explicitly specify a different namespace.

The following arenot supported:

  • Theglobal:: qualification.
  • Partially-qualified names. For example, you can't add@using BlazorSample to a component and then reference theNavMenu component in the app'sShared folder (Shared/NavMenu.razor) with<Shared.NavMenu></Shared.NavMenu>.

Partial class support

Components are generated asC# partial classes and are authored using either of the following approaches:

  • A single file contains C# code defined in one or more@code blocks, HTML markup, and Razor markup. Blazor project templates define their components using this single-file approach.
  • HTML and Razor markup are placed in a Razor file (.razor). C# code is placed in a code-behind file defined as a partial class (.cs).

Note

A component stylesheet that defines component-specific styles is a separate file (.css). Blazor CSS isolation is described later inASP.NET Core Blazor CSS isolation.

The following example shows the defaultCounter component with an@code block in an app generated from a Blazor project template. Markup and C# code are in the same file. This is the most common approach taken in component authoring.

Counter.razor:

@page "/counter"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>@code {    private int currentCount = 0;    private void IncrementCount() => currentCount++;}
@page "/counter"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>@code {    private int currentCount = 0;    private void IncrementCount() => currentCount++;}
@page "/counter"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>@code {    private int currentCount = 0;    private void IncrementCount()    {        currentCount++;    }}
@page "/counter"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>@code {    private int currentCount = 0;    private void IncrementCount()    {        currentCount++;    }}
@page "/counter"<h1>Counter</h1><p>Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>@code {    private int currentCount = 0;    private void IncrementCount()    {        currentCount++;    }}
@page "/counter"<h1>Counter</h1><p>Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>@code {    private int currentCount = 0;    private void IncrementCount()    {        currentCount++;    }}

The followingCounter component splits presentation HTML and Razor markup from the C# code using a code-behind file with a partial class. Splitting the markup from the C# code is favored by some organizations and developers to organize their component code to suit how they prefer to work. For example, the organization's UI expert can work on the presentation layer independently of another developer working on the component's C# logic. The approach is also useful when working with automatically-generated code or source generators. For more information, seePartial Classes and Methods (C# Programming Guide).

CounterPartialClass.razor:

@page "/counter-partial-class"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"<PageTitle>Counter</PageTitle><h1>Counter</h1><p role="status">Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"<h1>Counter</h1><p>Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"<h1>Counter</h1><p>Current count: @currentCount</p><button @onclick="IncrementCount">Click me</button>

CounterPartialClass.razor.cs:

namespace BlazorSample.Components.Pages;public partial class CounterPartialClass{    private int currentCount = 0;    private void IncrementCount() => currentCount++;}
namespace BlazorSample.Components.Pages;public partial class CounterPartialClass{    private int currentCount = 0;    private void IncrementCount() => currentCount++;}
namespace BlazorSample.Pages;public partial class CounterPartialClass{    private int currentCount = 0;    private void IncrementCount()    {        currentCount++;    }}
namespace BlazorSample.Pages{    public partial class CounterPartialClass    {        private int currentCount = 0;        private void IncrementCount()        {            currentCount++;        }    }}

@using directives in the_Imports.razor file are only applied to Razor files (.razor), not C# files (.cs). Add namespaces to a partial class file as needed.

Typical namespaces used by components:

using System.Net.Http;using System.Net.Http.Json;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Components.Authorization;using Microsoft.AspNetCore.Components.Forms;using Microsoft.AspNetCore.Components.Routing;using Microsoft.AspNetCore.Components.Sectionsusing Microsoft.AspNetCore.Components.Web;using static Microsoft.AspNetCore.Components.Web.RenderMode;using Microsoft.AspNetCore.Components.Web.Virtualization;using Microsoft.JSInterop;

Typical namespaces also include the namespace of the app and the namespace corresponding to the app'sComponents folder:

using BlazorSample;using BlazorSample.Components;

Additional folders can also be included, such as theLayout folder:

using BlazorSample.Components.Layout;
using System.Net.Http;using System.Net.Http.Json;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Components.Authorization;using Microsoft.AspNetCore.Components.Forms;using Microsoft.AspNetCore.Components.Routing;using Microsoft.AspNetCore.Components.Web;using Microsoft.AspNetCore.Components.Web.Virtualization;using Microsoft.JSInterop;

Typical namespaces also include the namespace of the app and the namespace corresponding to the app'sShared folder:

using BlazorSample;using BlazorSample.Shared;
using System.Net.Http;using Microsoft.AspNetCore.Components.Forms;using Microsoft.AspNetCore.Components.Routing;using Microsoft.AspNetCore.Components.Web;using Microsoft.JSInterop;

Typical namespaces also include the namespace of the app and the namespace corresponding to the app'sShared folder:

using BlazorSample;using BlazorSample.Shared;

Specify a base class

The@inherits directive is used to specify a base class for a component. Unlike usingpartial classes, which only split markup from C# logic, using a base class allows you to inherit C# code for use across a group of components that share the base class's properties and methods. Using base classes reduce code redundancy in apps and are useful when supplying base code from class libraries to multiple apps. For more information, seeInheritance in C# and .NET.

In the following example, theBlazorRocksBase1 base class derives fromComponentBase.

BlazorRocks1.razor:

@page "/blazor-rocks-1"@inherits BlazorRocksBase1<PageTitle>Blazor Rocks!</PageTitle><h1>Blazor Rocks! Example 1</h1><p>    @BlazorRocksText</p>
@page "/blazor-rocks-1"@inherits BlazorRocksBase1<PageTitle>Blazor Rocks!</PageTitle><h1>Blazor Rocks! Example 1</h1><p>    @BlazorRocksText</p>
@page "/blazor-rocks-1"@inherits BlazorRocksBase1<PageTitle>Blazor Rocks!</PageTitle><h1>Blazor Rocks! Example 1</h1><p>    @BlazorRocksText</p>
@page "/blazor-rocks-1"@inherits BlazorRocksBase1<PageTitle>Blazor Rocks!</PageTitle><h1>Blazor Rocks! Example 1</h1><p>    @BlazorRocksText</p>
@page "/blazor-rocks-1"@inherits BlazorRocksBase1<h1>Blazor Rocks! Example 1</h1><p>    @BlazorRocksText</p>
@page "/blazor-rocks-1"@inherits BlazorRocksBase1<h1>Blazor Rocks! Example 1</h1><p>    @BlazorRocksText</p>

BlazorRocksBase1.cs:

using Microsoft.AspNetCore.Components;namespace BlazorSample;public class BlazorRocksBase1 : ComponentBase{    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";}
using Microsoft.AspNetCore.Components;namespace BlazorSample;public class BlazorRocksBase1 : ComponentBase{    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";}
using Microsoft.AspNetCore.Components;namespace BlazorSample;public class BlazorRocksBase1 : ComponentBase{    public string BlazorRocksText { get; set; } =        "Blazor rocks the browser!";}
using Microsoft.AspNetCore.Components;namespace BlazorSample;public class BlazorRocksBase1 : ComponentBase{    public string BlazorRocksText { get; set; } =        "Blazor rocks the browser!";}
using Microsoft.AspNetCore.Components;namespace BlazorSample;public class BlazorRocksBase1 : ComponentBase{    public string BlazorRocksText { get; set; } =        "Blazor rocks the browser!";}
using Microsoft.AspNetCore.Components;namespace BlazorSample;public class BlazorRocksBase1 : ComponentBase{    public string BlazorRocksText { get; set; } =        "Blazor rocks the browser!";}

Routing

Routing in Blazor is achieved by providing a route template to each accessible component in the app with an@page directive. When a Razor file with an@page directive is compiled, the generated class is given aRouteAttribute specifying the route template. At runtime, the router searches for component classes with aRouteAttribute and renders whichever component has a route template that matches the requested URL.

The followingHelloWorld component uses a route template of/hello-world, and the rendered webpage for the component is reached at the relative URL/hello-world.

HelloWorld.razor:

@page "/hello-world"<PageTitle>Hello World!</PageTitle><h1>Hello World!</h1>
@page "/hello-world"<PageTitle>Hello World!</PageTitle><h1>Hello World!</h1>
@page "/hello-world"<h1>Hello World!</h1>
@page "/hello-world"<h1>Hello World!</h1>
@page "/hello-world"<h1>Hello World!</h1>
@page "/hello-world"<h1>Hello World!</h1>

The preceding component loads in the browser at/hello-world regardless of whether or not you add the component to the app's UI navigation. Optionally, components can be added to theNavMenu component so that a link to the component appears in the app's UI-based navigation.

For the precedingHelloWorld component, you can add aNavLink component to theNavMenu component. For more information, including descriptions of theNavLink andNavMenu components, seeASP.NET Core Blazor routing and navigation.

Markup

A component's UI is defined usingRazor syntax, which consists of Razor markup, C#, and HTML. When an app is compiled, the HTML markup and C# rendering logic are converted into a component class. The name of the generated class matches the name of the file.

Members of the component class are defined in one or more@code blocks. In@code blocks, component state is specified and processed with C#:

  • Property and field initializers.
  • Parameter values from arguments passed by parent components and route parameters.
  • Methods for user event handling, lifecycle events, and custom component logic.

Component members are used in rendering logic using C# expressions that start with the@ symbol. For example, a C# field is rendered by prefixing@ to the field name. The followingMarkup component evaluates and renders:

  • headingFontStyle for the CSS property valuefont-style of the heading element.
  • headingText for the content of the heading element.

Markup.razor:

@page "/markup"<PageTitle>Markup</PageTitle><h1>Markup Example</h1><h2>@headingText</h2>@code {    private string headingFontStyle = "italic";    private string headingText = "Put on your new Blazor!";}
@page "/markup"<PageTitle>Markup</PageTitle><h1>Markup Example</h1><h2>@headingText</h2>@code {    private string headingFontStyle = "italic";    private string headingText = "Put on your new Blazor!";}
@page "/markup"<h1>@headingText</h1>@code {    private string headingFontStyle = "italic";    private string headingText = "Put on your new Blazor!";}
@page "/markup"<h1>@headingText</h1>@code {    private string headingFontStyle = "italic";    private string headingText = "Put on your new Blazor!";}
@page "/markup"<h1>@headingText</h1>@code {    private string headingFontStyle = "italic";    private string headingText = "Put on your new Blazor!";}
@page "/markup"<h1>@headingText</h1>@code {    private string headingFontStyle = "italic";    private string headingText = "Put on your new Blazor!";}

Note

Examples throughout the Blazor documentation specify theprivate access modifier for private members. Private members are scoped to a component's class. However, C# assumes theprivate access modifier when no access modifier is present, so explicitly marking members "private" in your own code is optional. For more information on access modifiers, seeAccess Modifiers (C# Programming Guide).

The Blazor framework processes a component internally as arender tree, which is the combination of a component's DOM andCascading Style Sheet Object Model (CSSOM). After the component is initially rendered, the component's render tree is regenerated in response to events. Blazor compares the new render tree against the previous render tree and applies any modifications to the browser's DOM for display. For more information, seeASP.NET Core Razor component rendering.

Razor syntax for C# control structures, directives, and directive attributes are lowercase (examples:@if,@code,@bind). Property names are uppercase (example:@Body forLayoutComponentBase.Body).

Asynchronous methods (async) don't support returningvoid

The Blazor framework doesn't trackvoid-returning asynchronous methods (async). As a result, the entire process fails when an exception isn't caught ifvoid is returned. Always return aTask/ValueTask from asynchronous methods.

Nested components

Components can include other components by declaring them using HTML syntax. The markup for using a component looks like an HTML tag where the name of the tag is the component type.

Consider the followingHeading component, which can be used by other components to display a heading.

Heading.razor:

<h1>Heading Example</h1>@code {    private string headingFontStyle = "italic";}
<h1>Heading Example</h1>@code {    private string headingFontStyle = "italic";}
<h1>Heading Example</h1>@code {    private string headingFontStyle = "italic";}
<h1>Heading Example</h1>@code {    private string headingFontStyle = "italic";}
<h1>Heading Example</h1>@code {    private string headingFontStyle = "italic";}
<h1>Heading Example</h1>@code {    private string headingFontStyle = "italic";}

The following markup in theHeadingExample component renders the precedingHeading component at the location where the<Heading /> tag appears.

HeadingExample.razor:

@page "/heading-example"<PageTitle>Heading</PageTitle><h1>Heading Example</h1><Heading />
@page "/heading-example"<PageTitle>Heading</PageTitle><h1>Heading Example</h1><Heading />
@page "/heading-example"<Heading />
@page "/heading-example"<Heading />
@page "/heading-example"<Heading />
@page "/heading-example"<Heading />

If a component contains an HTML element with an uppercase first letter that doesn't match a component name within the same namespace, a warning is emitted indicating that the element has an unexpected name. Adding an@using directive for the component's namespace makes the component available, which resolves the warning. For more information, see theComponent name, class name, and namespace section.

TheHeading component example shown in this section doesn't have an@page directive, so theHeading component isn't directly accessible to a user via a direct request in the browser. However, any component with an@page directive can be nested in another component. If theHeading component was directly accessible by including@page "/heading" at the top of its Razor file, then the component would be rendered for browser requests at both/heading and/heading-example.

Component parameters

Component parameters pass data to components and are defined using publicC# properties on the component class with the[Parameter] attribute.

In the followingParameterChild component, component parameters include:

  • Built-in reference types.

  • A user-defined reference type (PanelBody) to pass a Bootstrap card body inBody.

    PanelBody.cs:

    namespace BlazorSample;public class PanelBody{    public string? Text { get; set; }    public string? Style { get; set; }}
    namespace BlazorSample;public class PanelBody{    public string? Text { get; set; }    public string? Style { get; set; }}
    public class PanelBody{    public string? Text { get; set; }    public string? Style { get; set; }}
    public class PanelBody{    public string? Text { get; set; }    public string? Style { get; set; }}
    public class PanelBody{    public string Text { get; set; }    public string Style { get; set; }}
    public class PanelBody{    public string Text { get; set; }    public string Style { get; set; }}

ParameterChild.razor:

<div>    <div>@Title</div>    <div>        <p>@Body.Text</p>        @if (Count is not null)        {            <p>The count is @Count.</p>        }    </div></div>@code {    [Parameter]    public string Title { get; set; } = "Set By Child";    [Parameter]    public PanelBody Body { get; set; } =        new()        {            Text = "Card content set by child.",            Style = "normal"        };    [Parameter]    public int? Count { get; set; }}
<div>    <div>@Title</div>    <div>        <p>@Body.Text</p>        @if (Count is not null)        {            <p>The count is @Count.</p>        }    </div></div>@code {    [Parameter]    public string Title { get; set; } = "Set By Child";    [Parameter]    public PanelBody Body { get; set; } =        new()        {            Text = "Card content set by child.",            Style = "normal"        };        [Parameter]    public int? Count { get; set; }}
<div>    <div>@Title</div>    <div>        <p>@Body.Text</p>        @if (Count is not null)        {            <p>The count is @Count.</p>        }    </div></div>@code {    [Parameter]    public string Title { get; set; } = "Set By Child";    [Parameter]    public PanelBody Body { get; set; } =        new()        {            Text = "Set by child.",            Style = "normal"        };    [Parameter]    public int? Count { get; set; }}
<div>    <div>@Title</div>    <div>        <p>@Body.Text</p>        @if (Count is not null)        {            <p>The count is @Count.</p>        }    </div></div>@code {    [Parameter]    public string Title { get; set; } = "Set By Child";    [Parameter]    public PanelBody Body { get; set; } =        new()        {            Text = "Set by child.",            Style = "normal"        };    [Parameter]    public int? Count { get; set; }}
<div>    <div>@Title</div>    <div>        <p>@Body.Text</p>        @if (Count is not null)        {            <p>The count is @Count.</p>        }    </div></div>@code {    [Parameter]    public string Title { get; set; } = "Set By Child";    [Parameter]    public PanelBody Body { get; set; } =        new()        {            Text = "Set by child.",            Style = "normal"        };    [Parameter]    public int? Count { get; set; }}
<div>    <div>@Title</div>    <div>        <p>@Body.Text</p>        @if (Count is not null)        {            <p>The count is @Count.</p>        }    </div></div>@code {    [Parameter]    public string Title { get; set; } = "Set By Child";    [Parameter]    public PanelBody Body { get; set; } =        new PanelBody()        {            Text = "Set by child.",            Style = "normal"        };    [Parameter]    public int? Count { get; set; }}

Warning

Providing initial values for component parameters is supported, but don't create a component that writes to its own parameters after the component is rendered for the first time. For more information, seeAvoid overwriting parameters in ASP.NET Core Blazor.

The component parameters of theParameterChild component can be set by arguments in the HTML tag that renders an instance of theParameterChild component. The following parent component renders twoParameterChild components:

  • The firstParameterChild component is rendered without supplying parameter arguments.
  • The secondParameterChild component receives values forTitle andBody from the parent component, which uses anexplicit C# expression to set the values of thePanelBody's properties.

Parameter1.razor:

@page "/parameter-1"<PageTitle>Parameter 1</PageTitle><h1>Parameter Example 1</h1><h1>Child component (without attribute values)</h1><ParameterChild /><h1>Child component (with attribute values)</h1><ParameterChild Title="Set by Parent"     Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

Parameter1.razor:

@page "/parameter-1"<PageTitle>Parameter 1</PageTitle><h1>Parameter Example 1</h1><h1>Child component (without attribute values)</h1><ParameterChild /><h1>Child component (with attribute values)</h1><ParameterChild Title="Set by Parent"     Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"<h1>Child component (without attribute values)</h1><ParameterChild /><h1>Child component (with attribute values)</h1><ParameterChild Title="Set by Parent"                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"<h1>Child component (without attribute values)</h1><ParameterChild /><h1>Child component (with attribute values)</h1><ParameterChild Title="Set by Parent"                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"<h1>Child component (without attribute values)</h1><ParameterChild /><h1>Child component (with attribute values)</h1><ParameterChild Title="Set by Parent"                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"<h1>Child component (without attribute values)</h1><ParameterChild /><h1>Child component (with attribute values)</h1><ParameterChild Title="Set by Parent"                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

The following rendered HTML markup from the parent component showsParameterChild component default values when the parent component doesn't supply component parameter values. When the parent component provides component parameter values, they replace theParameterChild component's default values.

Note

For clarity, most of the rendered CSS style classes and some elements aren't shown in the following rendered HTML markup. The main concept demonstrated by the following example is that the parent component assigned values to the child component using its component parameters.

<h1>Child component (without attribute values)</h1><div>Set By Child</div><div>    <p>Card content set by child.</p></div><h1>Child component (with attribute values)</h1><div>Set by Parent</div><div>    <p>Set by parent.</p></div>

Assign a C# field, property, or result of a method to a component parameter as an HTML attribute value. The value of the attribute can typically be any C# expression that matches the type of the parameter. The value of the attribute can optionally lead with aRazor reserved@ symbol, but it isn't required.

If the component parameter is of type string, then the attribute value is instead treated as a C# string literal. If you want to specify a C# expression instead, then use the@ prefix.

The following parent component displays four instances of the precedingParameterChild component and sets theirTitle parameter values to:

  • The value of thetitle field.
  • The result of theGetTitle C# method.
  • The current local date in long format withToLongDateString, which uses animplicit C# expression.
  • ThepanelData object'sTitle property.

The fifthParameterChild component instance also sets theCount parameter. Note how astring-typed parameter requires an@ prefix to ensure that an expression isn't treated as a string literal. However,Count is a nullable integer (System.Int32), soCount can receive the value ofcount without an@ prefix. You can establish an alternative code convention that requires developers in your organization to always prefix with@. Either way, we merely recommend that you adopt a consistent approach for how component parameters are passed in Razor markup.

Quotes around parameter attribute values are optional in most cases per the HTML5 specification. For example,Value=this is supported, instead ofValue="this". However, we recommend using quotes because it's easier to remember and widely adopted across web-based technologies.

Throughout the documentation, code examples:

  • Always use quotes. Example:Value="this".
  • Don't use the@ prefix with nonliterals unless required. Example:Count="count", wherecount is a number-typed variable.Count="@count" is a valid stylistic approach, but the documentation and examples don't adopt the convention.
  • Always avoid@ for literals, outside of Razor expressions. Example:IsFixed="true". This includes keywords (for example,this) andnull, but you can choose to use them if you wish. For example,IsFixed="@true" is uncommon but supported.

Parameter2.razor:

@page "/parameter-2"<PageTitle>Parameter 2</PageTitle><h1>Parameter Example 2</h1><ParameterChild Title="@title" /><ParameterChild Title="@GetTitle()" /><ParameterChild Title="@DateTime.Now.ToLongDateString()" /><ParameterChild Title="@panelData.Title" /><ParameterChild Title="String literal title" Count="count" />@code {    private string title = "From Parent field";    private PanelData panelData = new();    private int count = 12345;    private string GetTitle() => "From Parent method";    private class PanelData    {        public string Title { get; set; } = "From Parent object";    }}

Parameter2.razor:

@page "/parameter-2"<PageTitle>Parameter 2</PageTitle><h1>Parameter Example 2</h1><ParameterChild Title="@title" /><ParameterChild Title="@GetTitle()" /><ParameterChild Title="@DateTime.Now.ToLongDateString()" /><ParameterChild Title="@panelData.Title" /><ParameterChild Title="String literal title" Count="count" />@code {    private string title = "From Parent field";    private PanelData panelData = new();    private int count = 12345;    private string GetTitle() => "From Parent method";    private class PanelData    {        public string Title { get; set; } = "From Parent object";    }}

ParameterParent2.razor:

@page "/parameter-parent-2"<ParameterChild Title="@title" /><ParameterChild Title="@GetTitle()" /><ParameterChild Title="@DateTime.Now.ToLongDateString()" /><ParameterChild Title="@panelData.Title" /><ParameterChild Title="String literal title" Count="count" />@code {    private string title = "From Parent field";    private PanelData panelData = new();    private int count = 12345;    private string GetTitle()    {        return "From Parent method";    }    private class PanelData    {        public string Title { get; set; } = "From Parent object";    }}

ParameterParent2.razor:

@page "/parameter-parent-2"<ParameterChild Title="@title" /><ParameterChild Title="@GetTitle()" /><ParameterChild Title="@DateTime.Now.ToLongDateString()" /><ParameterChild Title="@panelData.Title" /><ParameterChild Title="String literal title" Count="count" />@code {    private string title = "From Parent field";    private PanelData panelData = new();    private int count = 12345;    private string GetTitle()    {        return "From Parent method";    }    private class PanelData    {        public string Title { get; set; } = "From Parent object";    }}

ParameterParent2.razor:

@page "/parameter-parent-2"<ParameterChild Title="@title" /><ParameterChild Title="@GetTitle()" /><ParameterChild Title="@DateTime.Now.ToLongDateString()" /><ParameterChild Title="@panelData.Title" /><ParameterChild Title="String literal title" Count="count" />@code {    private string title = "From Parent field";    private PanelData panelData = new PanelData();    private int count = 12345;    private string GetTitle()    {        return "From Parent method";    }    private class PanelData    {        public string Title { get; set; } = "From Parent object";    }}

Note

When assigning a C# member to a component parameter, don't prefix the parameter's HTML attribute with@.

Correct (Title is a string parameter,Count is a number-typed parameter):

<ParameterChild Title="@title" Count="count" />
<ParameterChild Title="@title" Count="@count" />

Incorrect:

<ParameterChild @Title="@title" @Count="count" />
<ParameterChild @Title="@title" @Count="@count" />

Unlike in Razor pages (.cshtml), Blazor can't perform asynchronous work in a Razor expression while rendering a component. This is because Blazor is designed for rendering interactive UIs. In an interactive UI, the screen must always display something, so it doesn't make sense to block the rendering flow. Instead, asynchronous work is performed during one of theasynchronous lifecycle events. After each asynchronous lifecycle event, the component may render again. The following Razor syntax isnot supported:

<ParameterChild Title="await ..." /><ParameterChild Title="@await ..." />

The code in the preceding example generates acompiler error when the app is built:

The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.

To obtain a value for theTitle parameter in the preceding example asynchronously, the component can use theOnInitializedAsync lifecycle event, as the following example demonstrates:

<ParameterChild Title="@title" />@code {    private string? title;        protected override async Task OnInitializedAsync()    {        title = await ...;    }}

For more information, seeASP.NET Core Razor component lifecycle.

Use of an explicit Razor expression to concatenate text with an expression result for assignment to a parameter isnot supported. The following example seeks to concatenate the text "Set by" with an object's property value. Although this syntax is supported in a Razor page (.cshtml), it isn't valid for assignment to the child'sTitle parameter in a component. The following Razor syntax isnot supported:

<ParameterChild Title="Set by @(panelData.Title)" />

The code in the preceding example generates acompiler error when the app is built:

Component attributes do not support complex content (mixed C# and markup).

To support the assignment of a composed value, use a method, field, or property. The following example performs the concatenation of "Set by" and an object's property value in the C# methodGetTitle:

Parameter3.razor:

@page "/parameter-3"<PageTitle>Parameter 3</PageTitle><h1>Parameter Example 3</h1><ParameterChild Title="@GetTitle()" />@code {    private PanelData panelData = new();    private string GetTitle() => $"Set by {panelData.Title}";    private class PanelData    {        public string Title { get; set; } = "Parent";    }}

Parameter3.razor:

@page "/parameter-3"<PageTitle>Parameter 3</PageTitle><h1>Parameter Example 3</h1><ParameterChild Title="@GetTitle()" />@code {    private PanelData panelData = new();    private string GetTitle() => $"Set by {panelData.Title}";    private class PanelData    {        public string Title { get; set; } = "Parent";    }}

ParameterParent3.razor:

@page "/parameter-parent-3"<ParameterChild Title="@GetTitle()" />@code {    private PanelData panelData = new();    private string GetTitle() => $"Set by {panelData.Title}";    private class PanelData    {        public string Title { get; set; } = "Parent";    }}

ParameterParent3.razor:

@page "/parameter-parent-3"<ParameterChild Title="@GetTitle()" />@code {    private PanelData panelData = new();    private string GetTitle() => $"Set by {panelData.Title}";    private class PanelData    {        public string Title { get; set; } = "Parent";    }}

ParameterParent3.razor:

@page "/parameter-parent-3"<ParameterChild Title="@GetTitle()" />@code {    private PanelData panelData = new();    private string GetTitle() => $"Set by {panelData.Title}";    private class PanelData    {        public string Title { get; set; } = "Parent";    }}

ParameterParent3.razor:

@page "/parameter-parent-3"<ParameterChild Title="@GetTitle()" />@code {    private PanelData panelData = new PanelData();    private string GetTitle() => $"Set by {panelData.Title}";    private class PanelData    {        public string Title { get; set; } = "Parent";    }}

For more information, seeRazor syntax reference for ASP.NET Core.

Warning

Providing initial values for component parameters is supported, but don't create a component that writes to its own parameters after the component is rendered for the first time. For more information, seeAvoid overwriting parameters in ASP.NET Core Blazor.

Component parameters should be declared asautomatically-implemented properties (auto properties), meaning that they shouldn't contain custom logic in theirget orset accessors. For example, the followingStartData property is an auto property:

[Parameter]public DateTime StartData { get; set; }

Don't place custom logic in theget orset accessor because component parameters are purely intended for use as a channel for a parent component to flow information to a child component. If aset accessor of a child component property contains logic that causes rerendering of the parent component, an infinite rendering loop results. Other side effects include unexpected extra renderings and parameter value overwrites.

To transform a received parameter value:

  • Leave the parameter property as an auto-property to represent the supplied raw data.
  • Create a different property or method to supply the transformed data based on the parameter property.

OverrideOnParametersSetAsync to transform a received parameter each time new data is received.

Writing an initial value to a component parameter is supported because initial value assignments don't interfere with the Blazor's automatic component rendering. The following assignment of the current localDateTime withDateTime.Now toStartData is valid syntax in a component:

[Parameter]public DateTime StartData { get; set; } = DateTime.Now;

After the initial assignment ofDateTime.Now, donot assign a value toStartData in developer code. For more information, seeAvoid overwriting parameters in ASP.NET Core Blazor.

Apply the[EditorRequired] attribute to specify a required component parameter. If a parameter value isn't provided, editors or build tools may display warnings to the user. This attribute is only valid on properties also marked with the[Parameter] attribute. TheEditorRequiredAttribute is enforced at design-time and when the app is built. The attribute isn't enforced at runtime, and it doesn't guarantee a non-null parameter value.

[Parameter][EditorRequired]public string? Title { get; set; }

Single-line attribute lists are also supported:

[Parameter, EditorRequired]public string? Title { get; set; }

Don't use therequired modifier orinit accessor on component parameter properties. Components are usually instantiated and assigned parameter values usingreflection, which bypasses the guarantees thatinit andrequired are designed to make. Instead, use the[EditorRequired] attribute to specify a required component parameter.

Don't use theinit accessor on component parameter properties because setting component parameter values withParameterView.SetParameterProperties usesreflection, which bypasses the init-only setter restriction. Use the[EditorRequired] attribute to specify a required component parameter.

Don't use theinit accessor on component parameter properties because setting component parameter values withParameterView.SetParameterProperties usesreflection, which bypasses the init-only setter restriction.

Tuples (API documentation) are supported for component parameters andRenderFragment types. The following component parameter example passes three values in aTuple:

RenderTupleChild.razor:

<div>    <div>Tuple Card</div>    <div>        <ul>            <li>Integer: @Data?.Item1</li>            <li>String: @Data?.Item2</li>            <li>Boolean: @Data?.Item3</li>        </ul>    </div></div>@code {    [Parameter]    public (int, string, bool)? Data { get; set; }}

RenderTupleParent.razor:

@page "/render-tuple-parent"<PageTitle>Render Tuple Parent</PageTitle><h1>Render Tuple Parent Example</h1><RenderTupleChild Data="data" />@code {    private (int, string, bool) data = new(999, "I aim to misbehave.", true);}

Named tuples are supported, as seen in the following example:

NamedTupleChild.razor:

<div>    <div>Tuple Card</div>    <div>        <ul>            <li>Integer: @Data?.TheInteger</li>            <li>String: @Data?.TheString</li>            <li>Boolean: @Data?.TheBoolean</li>        </ul>    </div></div>@code {    [Parameter]    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }}

NamedTuples.razor:

@page "/named-tuples"<PageTitle>Named Tuples</PageTitle><h1>Named Tuples Example</h1><NamedTupleChild Data="data" />@code {    private (int TheInteger, string TheString, bool TheBoolean) data =         new(999, "I aim to misbehave.", true);}

Quote ©2005Universal Pictures:Serenity (Nathan Fillion)

Tuples (API documentation) are supported for component parameters andRenderFragment types. The following component parameter example passes three values in aTuple:

RenderTupleChild.razor:

<div>    <div>Tuple Card</div>    <div>        <ul>            <li>Integer: @Data?.Item1</li>            <li>String: @Data?.Item2</li>            <li>Boolean: @Data?.Item3</li>        </ul>    </div></div>@code {    [Parameter]    public (int, string, bool)? Data { get; set; }}

RenderTupleParent.razor:

@page "/render-tuple-parent"<PageTitle>Render Tuple Parent</PageTitle><h1>Render Tuple Parent Example</h1><RenderTupleChild Data="data" />@code {    private (int, string, bool) data = new(999, "I aim to misbehave.", true);}

Named tuples are supported, as seen in the following example:

NamedTupleChild.razor:

<div>    <div>Tuple Card</div>    <div>        <ul>            <li>Integer: @Data?.TheInteger</li>            <li>String: @Data?.TheString</li>            <li>Boolean: @Data?.TheBoolean</li>        </ul>    </div></div>@code {    [Parameter]    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }}

NamedTuples.razor:

@page "/named-tuples"<PageTitle>Named Tuples</PageTitle><h1>Named Tuples Example</h1><NamedTupleChild Data="data" />@code {    private (int TheInteger, string TheString, bool TheBoolean) data =         new(999, "I aim to misbehave.", true);}

Quote ©2005Universal Pictures:Serenity (Nathan Fillion)

Tuples (API documentation) are supported for component parameters andRenderFragment types. The following component parameter example passes three values in aTuple:

RenderTupleChild.razor:

<div>    <div><code>Tuple</code> Card</div>    <div>        <ul>            <li>Integer: @Data?.Item1</li>            <li>String: @Data?.Item2</li>            <li>Boolean: @Data?.Item3</li>        </ul>    </div></div>@code {    [Parameter]    public (int, string, bool)? Data { get; set; }}

RenderTupleParent.razor:

@page "/render-tuple-parent"<h1>Render Tuple Parent</h1><RenderTupleChild Data="data" />@code {    private (int, string, bool) data = new(999, "I aim to misbehave.", true);}

Named tuples are supported, as seen in the following example:

RenderNamedTupleChild.razor:

<div>    <div><code>Tuple</code> Card</div>    <div>        <ul>            <li>Integer: @Data?.TheInteger</li>            <li>String: @Data?.TheString</li>            <li>Boolean: @Data?.TheBoolean</li>        </ul>    </div></div>@code {    [Parameter]    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }}

RenderNamedTupleParent.razor:

@page "/render-named-tuple-parent"<h1>Render Named Tuple Parent</h1><RenderNamedTupleChild Data="data" />@code {    private (int TheInteger, string TheString, bool TheBoolean) data =         new(999, "I aim to misbehave.", true);}

Quote ©2005Universal Pictures:Serenity (Nathan Fillion)

Route parameters

Components can specify route parameters in the route template of the@page directive. TheBlazor router uses route parameters to populate corresponding component parameters.

RouteParameter1.razor:

@page "/route-parameter-1/{text}"<PageTitle>Route Parameter 1</PageTitle><h1>Route Parameter Example 1</h1><p>Blazor is @Text!</p>@code {    [Parameter]    public string? Text { get; set; }}
@page "/route-parameter-1/{text}"<PageTitle>Route Parameter 1</PageTitle><h1>Route Parameter Example 1</h1><p>Blazor is @Text!</p>@code {    [Parameter]    public string? Text { get; set; }}
@page "/route-parameter-1/{text}"<h1>Blazor is @Text!</h1>@code {    [Parameter]    public string? Text { get; set; }}
@page "/route-parameter-1/{text}"<h1>Blazor is @Text!</h1>@code {    [Parameter]    public string? Text { get; set; }}
@page "/route-parameter-1/{text}"<h1>Blazor is @Text!</h1>@code {    [Parameter]    public string Text { get; set; }}
@page "/route-parameter-1/{text}"<h1>Blazor is @Text!</h1>@code {    [Parameter]    public string Text { get; set; }}

For more information, see theRoute parameters section ofASP.NET Core Blazor routing and navigation. Optional route parameters are also supported and covered in the same section. For information on catch-all route parameters ({*pageRoute}), which capture paths across multiple folder boundaries, see theCatch-all route parameters section ofASP.NET Core Blazor routing and navigation.

For more information, see theRoute parameters section ofASP.NET Core Blazor routing and navigation. Optional route parameters aren't supported, so two@page directives are required (see theRoute parameters section for more information). For information on catch-all route parameters ({*pageRoute}), which capture paths across multiple folder boundaries, see theCatch-all route parameters section ofASP.NET Core Blazor routing and navigation.

Warning

With compression, which is enabled by default, avoid creating secure (authenticated/authorized) interactive server-side components that render data from untrusted sources. Untrusted sources include route parameters, query strings, data from JS interop, and any other source of data that a third-party user can control (databases, external services). For more information, seeASP.NET Core Blazor SignalR guidance andThreat mitigation guidance for ASP.NET Core Blazor interactive server-side rendering.

Child content render fragments

Components can set the content of another component. The assigning component provides the content between the child component's opening and closing tags.

In the following example, theRenderFragmentChild component has aChildContent component parameter that represents a segment of the UI to render as aRenderFragment. The position ofChildContent in the component's Razor markup is where the content is rendered in the final HTML output.

RenderFragmentChild.razor:

<div>    <div>Child content</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public RenderFragment? ChildContent { get; set; }}
<div>    <div>Child content</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public RenderFragment? ChildContent { get; set; }}
<div>    <div>Child content</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public RenderFragment? ChildContent { get; set; }}
<div>    <div>Child content</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public RenderFragment? ChildContent { get; set; }}
<div>    <div>Child content</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public RenderFragment ChildContent { get; set; }}
<div>    <div>Child content</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public RenderFragment ChildContent { get; set; }}

Important

The property receiving theRenderFragment content must be namedChildContent by convention.

Event callbacks aren't supported forRenderFragment.

The following component provides content for rendering theRenderFragmentChild by placing the content inside the child component's opening and closing tags.

RenderFragments.razor:

@page "/render-fragments"<PageTitle>Render Fragments</PageTitle><h1>Render Fragments Example</h1><RenderFragmentChild>    Content of the child component is supplied    by the parent component.</RenderFragmentChild>

RenderFragments.razor:

@page "/render-fragments"<PageTitle>Render Fragments</PageTitle><h1>Render Fragments Example</h1><RenderFragmentChild>    Content of the child component is supplied    by the parent component.</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"<h1>Render child content</h1><RenderFragmentChild>    Content of the child component is supplied    by the parent component.</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"<h1>Render child content</h1><RenderFragmentChild>    Content of the child component is supplied    by the parent component.</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"<h1>Render child content</h1><RenderFragmentChild>    Content of the child component is supplied    by the parent component.</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"<h1>Render child content</h1><RenderFragmentChild>    Content of the child component is supplied    by the parent component.</RenderFragmentChild>

Render fragments are used to render child content throughout Blazor apps and are described with examples in the following articles and article sections:

Note

Blazor framework'sbuilt-in Razor components use the sameChildContent component parameter convention to set their content. You can see the components that set child content by searching for the component parameter property nameChildContent in theAPI documentation (filters API with the search term "ChildContent").

Render fragments for reusable rendering logic

You can factor out child components purely as a way of reusing rendering logic. In any component's@code block, define aRenderFragment and render the fragment from any location as many times as needed:

@RenderWelcomeInfo<p>Render the welcome info a second time:</p>@RenderWelcomeInfo@code {    private RenderFragment RenderWelcomeInfo =  @<p>Welcome to your new app!</p>;}

For more information, seeReuse rendering logic.

Loop variables with component parameters and child content

Rendering components inside afor loop requires a local index variable if the incrementing loop variable is used by the component's parameters orRenderFragment child content.

Consider the followingRenderFragmentChild2 component that has both a component parameter (Id) and a render fragment to display child content (ChildContent).

RenderFragmentChild2.razor:

<div>    <div>Child content (@Id)</div>    <div>@ChildContent</div></div>@code {    [Parameter]    public string? Id { get; set; }    [Parameter]    public RenderFragment? ChildContent { get; set; }}

When rendering theRenderFragmentChild2 component in a parent component, use a local index variable (ct in the following example) instead of the loop variable (c) when assigning the component parameter value and providing the child component's content:

@for (int c = 1; c < 4; c++){    var ct = c;    <RenderFragmentChild2Child{ct}")">        Count: @ct    </RenderFragmentChild2>}

Alternatively, use aforeach loop withEnumerable.Range instead of afor loop:

@foreach (var c in Enumerable.Range(1, 3)){    <RenderFragmentChild2Child{c}")">        Count: @c    </RenderFragmentChild2>}

Capture references to components

Component references provide a way to reference a component instance for issuing commands. To capture a component reference:

  • Add an@ref attribute to the child component.
  • Define a field with the same type as the child component.

When the component is rendered, the field is populated with the component instance. You can then invoke .NET methods on the instance.

Consider the followingReferenceChild component that logs a message when itsChildMethod is called.

ReferenceChild.razor:

@inject ILogger<ReferenceChild> Logger@if (value > 0){    <p>        <code>value</code>: @value    </p>}@code {    private int value;    public void ChildMethod(int value)    {        Logger.LogInformation("Received {Value} in ChildMethod", value);        this.value = value;        StateHasChanged();    }}
@inject ILogger<ReferenceChild> Logger@if (value > 0){    <p>        <code>value</code>: @value    </p>}@code {    private int value;    public void ChildMethod(int value)    {        Logger.LogInformation("Received {Value} in ChildMethod", value);        this.value = value;        StateHasChanged();    }}
@using Microsoft.Extensions.Logging@inject ILogger<ReferenceChild> Logger@code {    public void ChildMethod(int value)    {        Logger.LogInformation("Received {Value} in ChildMethod", value);    }}
@using Microsoft.Extensions.Logging@inject ILogger<ReferenceChild> Logger@code {    public void ChildMethod(int value)    {        Logger.LogInformation("Received {Value} in ChildMethod", value);    }}
@using Microsoft.Extensions.Logging@inject ILogger<ReferenceChild> Logger@code {    public void ChildMethod(int value)    {        Logger.LogInformation("Received {Value} in ChildMethod", value);    }}
@using Microsoft.Extensions.Logging@inject ILogger<ReferenceChild> Logger@code {    public void ChildMethod(int value)    {        Logger.LogInformation("Received {Value} in ChildMethod", value);    }}

A component reference is only populated after the component is rendered and its output includesReferenceChild's element. Until the component is rendered, there's nothing to reference. Don't attempt to call a referenced component method to an event handler directly (for example,@onclick="childComponent!.ChildMethod(5)") because the reference variable may not be assigned at the time the click event is assigned.

To manipulate component references after the component has finished rendering, use theOnAfterRender orOnAfterRenderAsync methods.

The following example uses the precedingReferenceChild component.

ReferenceParent.razor:

@page "/reference-parent"<div>    <button @onclick="@(() => childComponent1!.ChildMethod(5))">        Call <code>ReferenceChild.ChildMethod</code> (first instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent1" /></div><div>    <button @onclick="CallChildMethod">        Call <code>ReferenceChild.ChildMethod</code> (second instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent2" /></div>@code {    private ReferenceChild? childComponent1;    private ReferenceChild? childComponent2;    private void CallChildMethod() => childComponent2!.ChildMethod(5);}
@page "/reference-parent"<div>    <button @onclick="@(() => childComponent1!.ChildMethod(5))">        Call <code>ReferenceChild.ChildMethod</code> (first instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent1" /></div><div>    <button @onclick="CallChildMethod">        Call <code>ReferenceChild.ChildMethod</code> (second instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent2" /></div>@code {    private ReferenceChild? childComponent1;    private ReferenceChild? childComponent2;    private void CallChildMethod() => childComponent2!.ChildMethod(5);}
@page "/reference-parent"<div>    <button @onclick="@(() => childComponent1!.ChildMethod(5))">        Call <code>ReferenceChild.ChildMethod</code> (first instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent1" /></div><div>    <button @onclick="CallChildMethod">        Call <code>ReferenceChild.ChildMethod</code> (second instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent2" /></div>@code {    private ReferenceChild? childComponent1;    private ReferenceChild? childComponent2;    private void CallChildMethod()    {        childComponent2!.ChildMethod(5);    }}
@page "/reference-parent"<div>    <button @onclick="@(() => childComponent1!.ChildMethod(5))">        Call <code>ReferenceChild.ChildMethod</code> (first instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent1" /></div><div>    <button @onclick="CallChildMethod">        Call <code>ReferenceChild.ChildMethod</code> (second instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent2" /></div>@code {    private ReferenceChild? childComponent1;    private ReferenceChild? childComponent2;    private void CallChildMethod()    {        childComponent2!.ChildMethod(5);    }}
@page "/reference-parent"<div>    <button @onclick="@(() => childComponent1!.ChildMethod(5))">        Call <code>ReferenceChild.ChildMethod</code> (first instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent1" /></div><div>    <button @onclick="CallChildMethod">        Call <code>ReferenceChild.ChildMethod</code> (second instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent2" /></div>@code {    private ReferenceChild childComponent1;    private ReferenceChild childComponent2;    private void CallChildMethod()    {        childComponent2!.ChildMethod(5);    }}
@page "/reference-parent"<div>    <button @onclick="@(() => childComponent1!.ChildMethod(5))">        Call <code>ReferenceChild.ChildMethod</code> (first instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent1" /></div><div>    <button @onclick="CallChildMethod">        Call <code>ReferenceChild.ChildMethod</code> (second instance)         with an argument of 5    </button>    <ReferenceChild @ref="childComponent2" /></div>@code {    private ReferenceChild childComponent1;    private ReferenceChild childComponent2;    private void CallChildMethod()    {        childComponent2!.ChildMethod(5);    }}

While capturing component references use a similar syntax tocapturing element references, capturing component references isn't a JavaScript interop feature. Component references aren't passed to JavaScript code. Component references are only used in .NET code.

Important

Donot use component references to mutate the state of child components. Instead, use normal declarative component parameters to pass data to child components. Use of component parameters result in child components that rerender at the correct times automatically. For more information, see thecomponent parameters section and theASP.NET Core Blazor data binding article.

Apply an attribute

Attributes can be applied to components with the@attribute directive. The following example applies the[Authorize] attribute to the component's class:

@page "/"@attribute [Authorize]

Conditional HTML element attributes and DOM properties

Blazor adopts the following general behaviors:

  • For HTML attributes, Blazor sets or removes the attribute conditionally based on the .NET value. If the .NET value isfalse ornull, the attribute isn't set or is removed if it was previously set.
  • For DOM properties, such aschecked orvalue, Blazor sets the DOM property based on the .NET value. If the .NET value isfalse ornull, the DOM property is reset to a default value.

Which Razor syntax attributes correspond to HTML attributes and which ones correspond to DOM properties remains undocumented because this is a framework implementation detail that might change without notice.

Warning

Some HTML attributes, such asaria-pressed, must have a string value of either "true" or "false". Since they require a string value and not a boolean, you must use a .NETstring and not abool for their value. This is a requirement set by browser DOM APIs.

Raw HTML

Strings are normally rendered using DOM text nodes, which means that any markup they may contain is ignored and treated as literal text. To render raw HTML, wrap the HTML content in aMarkupString value. The value is parsed as HTML or SVG and inserted into the DOM.

Warning

Rendering raw HTML constructed from any untrusted source is asecurity risk and shouldalways be avoided.

The following example shows using theMarkupString type to add a block of static HTML content to the rendered output of a component.

MarkupStrings.razor:

@page "/markup-strings"<PageTitle>Markup Strings</PageTitle><h1>Markup Strings Example</h1>@((MarkupString)myMarkup)@code {    private string myMarkup =        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";}

MarkupStrings.razor:

@page "/markup-strings"<PageTitle>Markup Strings</PageTitle><h1>Markup Strings Example</h1>@((MarkupString)myMarkup)@code {    private string myMarkup =        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";}

MarkupStringExample.razor:

@page "/markup-string-example"@((MarkupString)myMarkup)@code {    private string myMarkup =        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";}

MarkupStringExample.razor:

@page "/markup-string-example"@((MarkupString)myMarkup)@code {    private string myMarkup =        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";}

MarkupStringExample.razor:

@page "/markup-string-example"@((MarkupString)myMarkup)@code {    private string myMarkup =        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";}

MarkupStringExample.razor:

@page "/markup-string-example"@((MarkupString)myMarkup)@code {    private string myMarkup =        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";}

Razor templates

Render fragments can be defined using Razor template syntax to define a UI snippet. Razor templates use the following format:

@<{HTML tag}>...</{HTML tag}>

The following example illustrates how to specifyRenderFragment andRenderFragment<TValue> values and render templates directly in a component. Render fragments can also be passed as arguments totemplated components.

RazorTemplate.razor:

@page "/razor-template"<PageTitle>Razor Template</PageTitle><h1>Razor Template Example</h1>@timeTemplate@petTemplate(new Pet { Name = "Nutty Rex" })@code {    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;    private class Pet    {        public string? Name { get; set; }    }}
@page "/razor-template"<PageTitle>Razor Template</PageTitle><h1>Razor Template Example</h1>@timeTemplate@petTemplate(new Pet { Name = "Nutty Rex" })@code {    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;    private class Pet    {        public string? Name { get; set; }    }}
@page "/razor-template"@timeTemplate@petTemplate(new Pet { Name = "Nutty Rex" })@code {    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;    private class Pet    {        public string? Name { get; set; }    }}
@page "/razor-template"@timeTemplate@petTemplate(new Pet { Name = "Nutty Rex" })@code {    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;    private class Pet    {        public string? Name { get; set; }    }}
@page "/razor-template"@timeTemplate@petTemplate(new Pet { Name = "Nutty Rex" })@code {    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;    private class Pet    {        public string Name { get; set; }    }}
@page "/razor-template"@timeTemplate@petTemplate(new Pet { Name = "Nutty Rex" })@code {    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;    private class Pet    {        public string Name { get; set; }    }}

Rendered output of the preceding code:

<p>The time is 4/19/2021 8:54:46 AM.</p><p>Pet: Nutty Rex</p>

Static assets

Blazor follows the convention of ASP.NET Core apps for static assets. Static assets are located in the project'sweb root (wwwroot) folder or folders under thewwwroot folder.

Use a base-relative path (/) to refer to the web root for a static asset. In the following example,logo.png is physically located in the{PROJECT ROOT}/wwwroot/images folder.{PROJECT ROOT} is the app's project root.

<img alt="Company logo" src="/images/logo.png" />

Components donot support tilde-slash notation (~/).

For information on setting an app's base path, seeASP.NET Core Blazor app base path.

Tag Helpers aren't supported in components

Tag Helpers aren't supported in components. To provide Tag Helper-like functionality in Blazor, create a component with the same functionality as the Tag Helper and use the component instead.

Scalable Vector Graphics (SVG) images

Since Blazor renders HTML, browser-supported images, includingScalable Vector Graphics (SVG) images (.svg), are supported via the<img> tag:

<img alt="Example image" src="image.svg" />

Similarly, SVG images are supported in the CSS rules of a stylesheet file (.css):

.element-class {    background-image: url("image.svg");}

Blazor supports the<foreignObject> element to display arbitrary HTML within an SVG. The markup can represent arbitrary HTML, aRenderFragment, or a Razor component.

The following example demonstrates:

  • Display of astring (@message).
  • Two-way binding with an<input> element and avalue field.
  • ARobot component.
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">    <rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black"         fill="none" />    <foreignObject x="20" y="20" width="160" height="160">        <p>@message</p>    </foreignObject></svg><svg xmlns="http://www.w3.org/2000/svg">    <foreignObject width="200" height="200">        <label>            Two-way binding:            <input @bind="value" @bind:event="oninput" />        </label>    </foreignObject></svg><svg xmlns="http://www.w3.org/2000/svg">    <foreignObject>        <Robot />    </foreignObject></svg>@code {    private string message = "Lorem ipsum dolor sit amet, consectetur adipiscing " +        "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";    private string? value;}

Whitespace rendering behavior

Unless the@preservewhitespace directive is used with a value oftrue, extra whitespace is removed if:

  • Leading or trailing within an element.
  • Leading or trailing within aRenderFragment/RenderFragment<TValue> parameter (for example, child content passed to another component).
  • It precedes or follows a C# code block, such as@if or@foreach.

Whitespace removal might affect the rendered output when using a CSS rule, such aswhite-space: pre. To disable this performance optimization and preserve the whitespace, take one of the following actions:

  • Add the@preservewhitespace true directive at the top of the Razor file (.razor) to apply the preference to a specific component.
  • Add the@preservewhitespace true directive inside an_Imports.razor file to apply the preference to a subdirectory or to the entire project.

In most cases, no action is required, as apps typically continue to behave normally (but faster). If stripping whitespace causes a rendering problem for a particular component, use@preservewhitespace true in that component to disable this optimization.

Whitespace is retained in a component's source markup. Whitespace-only text renders in the browser's DOM even when there's no visual effect.

Consider the following component markup:

<ul>    @foreach (var item in Items)    {        <li>            @item.Text        </li>    }</ul>

The preceding example renders the following unnecessary whitespace:

  • Outside of the@foreach code block.
  • Around the<li> element.
  • Around the@item.Text output.

A list of 100 items results in over 400 areas of whitespace. None of the extra whitespace visually affects the rendered output.

When rendering static HTML for components, whitespace inside a tag isn't preserved. For example, view the rendered output of the following<img> tag in a component Razor file (.razor):

<img     alt="Example image"   src="img.png"     />

Whitespace isn't preserved from the preceding markup:

<img alt="Example image" src="img.png" />

Root component

Aroot Razor component (root component) is the first component loaded of any component hierarchy created by the app.

In an app created from the Blazor Web App project template, theApp component (App.razor) is specified as the default root component by the type parameter declared for the call toMapRazorComponents<TRootComponent> in the server-sideProgram file. The following example shows the use of theApp component as the root component, which is the default for an app created from the Blazor project template:

app.MapRazorComponents<App>();

Note

Making a root component interactive, such as theApp component, isn't supported.

In an app created from the Blazor Server project template, theApp component (App.razor) is specified as the default root component inPages/_Host.cshtml using theComponent Tag Helper:

<component type="typeof(App)" render-mode="ServerPrerendered" />

In an app created from the Blazor WebAssembly project template, theApp component (App.razor) is specified as the default root component in theProgram file:

builder.RootComponents.Add<App>("#app");

In the preceding code, the CSS selector,#app, indicates that theApp component is specified for the<div> inwwwroot/index.html with anid ofapp:

<div>...</app>

MVC and Razor Pages apps can also use theComponent Tag Helper to register statically-rendered Blazor WebAssembly root components:

<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

Statically-rendered components can only be added to the app. They can't be removed or updated afterwards.

For more information, see the following resources:

Collaborate with us on GitHub
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, seeour contributor guide.

Feedback

Was this page helpful?

YesNoNo

Need help with this topic?

Want to try using Ask Learn to clarify or guide you through this topic?

Suggest a fix?

  • Last updated on

In this article

Was this page helpful?

YesNo
NoNeed help with this topic?

Want to try using Ask Learn to clarify or guide you through this topic?

Suggest a fix?