ASP.NET Core Blazor layouts
Note
This isn't the latest version of this article. For the current release, see the .NET 8 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see .NET and .NET Core Support Policy. For the current release, see the .NET 8 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 8 version of this article.
This article explains how to create reusable layout components for Blazor apps.
Usefulness of Blazor layouts
Some app elements, such as menus, copyright messages, and company logos, are usually part of app's overall presentation. Placing a copy of the markup for these elements into all of the components of an app isn't efficient. Every time that one of these elements is updated, every component that uses the element must be updated. This approach is costly to maintain and can lead to inconsistent content if an update is missed. Layouts solve these problems.
A Blazor layout is a Razor component that shares markup with components that reference it. Layouts can use data binding, dependency injection, and other features of components.
Layout components
Create a layout component
To create a layout component:
- Create a Razor component defined by a Razor template or C# code. Layout components based on a Razor template use the
.razor
file extension just like ordinary Razor components. Because layout components are shared across an app's components, they're usually placed in the app'sShared
orLayout
folder. However, layouts can be placed in any location accessible to the components that use it. For example, a layout can be placed in the same folder as the components that use it. - Inherit the component from LayoutComponentBase. The LayoutComponentBase defines a Body property (RenderFragment type) for the rendered content inside the layout.
- Use the Razor syntax
@Body
to specify the location in the layout markup where the content is rendered.
Note
For more information on RenderFragment, see ASP.NET Core Razor components.
The following DoctorWhoLayout
component shows the Razor template of a layout component. The layout inherits LayoutComponentBase and sets the @Body
between the navigation bar (<nav>...</nav>
) and the footer (<footer>...</footer>
).
DoctorWhoLayout.razor
:
@inherits LayoutComponentBase
<PageTitle>Doctor Who® Database</PageTitle>
<header>
<h1>Doctor Who® Database</h1>
</header>
<nav>
<a href="main-list">Main Episode List</a>
<a href="search">Search</a>
<a href="new">Add Episode</a>
</nav>
@Body
<footer>
@TrademarkMessage
</footer>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
<PageTitle>Doctor Who® Database</PageTitle>
<header>
<h1>Doctor Who® Database</h1>
</header>
<nav>
<a href="main-list">Main Episode List</a>
<a href="search">Search</a>
<a href="new">Add Episode</a>
</nav>
@Body
<footer>
@TrademarkMessage
</footer>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
<header>
<h1>Doctor Who™ Episode Database</h1>
</header>
<nav>
<a href="main-list">Main Episode List</a>
<a href="search">Search</a>
<a href="new">Add Episode</a>
</nav>
@Body
<footer>
@TrademarkMessage
</footer>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
<header>
<h1>Doctor Who™ Episode Database</h1>
</header>
<nav>
<a href="main-list">Main Episode List</a>
<a href="search">Search</a>
<a href="new">Add Episode</a>
</nav>
@Body
<footer>
@TrademarkMessage
</footer>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
<header>
<h1>Doctor Who™ Episode Database</h1>
</header>
<nav>
<a href="main-list">Main Episode List</a>
<a href="search">Search</a>
<a href="new">Add Episode</a>
</nav>
@Body
<footer>
@TrademarkMessage
</footer>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
<header>
<h1>Doctor Who™ Episode Database</h1>
</header>
<nav>
<a href="main-list">Main Episode List</a>
<a href="search">Search</a>
<a href="new">Add Episode</a>
</nav>
@Body
<footer>
@TrademarkMessage
</footer>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
MainLayout
component
In an app created from a Blazor project template, the MainLayout
component is the app's default layout. Blazor's layout adopts the Flexbox layout model (MDN documentation) (W3C specification).
Blazor's CSS isolation feature applies isolated CSS styles to the MainLayout
component. By convention, the styles are provided by the accompanying stylesheet of the same name, MainLayout.razor.css
. The ASP.NET Core framework implementation of the stylesheet is available for inspection in the ASP.NET Core reference source (dotnet/aspnetcore
GitHub repository):
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 the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
Blazor's CSS isolation feature applies isolated CSS styles to the MainLayout
component. By convention, the styles are provided by the accompanying stylesheet of the same name, MainLayout.razor.css
. The ASP.NET Core framework implementation of the stylesheet is available for inspection in the ASP.NET Core reference source (dotnet/aspnetcore
GitHub repository):
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 the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
Apply a layout
Make the layout namespace available
Layout file locations and namespaces changed over time for the Blazor framework. Depending on the version of Blazor and type of Blazor app that you're building, you may need to indicate the layout's namespace when using it. When referencing a layout implementation and the layout isn't found without indicating the layout's namespace, take any of the following approaches:
Add an
@using
directive to the_Imports.razor
file for the location of the layouts. In the following example, a folder of layouts with the nameLayout
is inside aComponents
folder, and the app's namespace isBlazorSample
:@using BlazorSample.Components.Layout
Add an
@using
directive at the top of the component definition where the layout is used:@using BlazorSample.Components.Layout @layout DoctorWhoLayout
Fully qualify the namespace of the layout where it's used:
@layout BlazorSample.Components.Layout.DoctorWhoLayout
Apply a layout to a component
Use the @layout
Razor directive to apply a layout to a routable Razor component that has an @page
directive. The compiler converts @layout
into a LayoutAttribute and applies the attribute to the component class.
The content of the following Episodes
component is inserted into the DoctorWhoLayout
at the position of @Body
.
Episodes.razor
:
@page "/episodes"
@layout DoctorWhoLayout
<h2>Doctor Who® Episodes</h2>
<ul>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfknq">
<em>The Ribos Operation</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfdsb">
<em>The Sunmakers</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vhc26">
<em>Nightmare of Eden</em>
</a>
</li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout
<h2>Doctor Who® Episodes</h2>
<ul>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfknq">
<em>The Ribos Operation</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfdsb">
<em>The Sunmakers</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vhc26">
<em>Nightmare of Eden</em>
</a>
</li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout
<h2>Episodes</h2>
<ul>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfknq">
<em>The Ribos Operation</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfdsb">
<em>The Sun Makers</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vhc26">
<em>Nightmare of Eden</em>
</a>
</li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout
<h2>Episodes</h2>
<ul>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfknq">
<em>The Ribos Operation</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfdsb">
<em>The Sun Makers</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vhc26">
<em>Nightmare of Eden</em>
</a>
</li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout
<h2>Episodes</h2>
<ul>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfknq">
<em>The Ribos Operation</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vfdsb">
<em>The Sun Makers</em>
</a>
</li>
<li>
<a href="https://www.bbc.co.uk/programmes/p00vhc26">
<em>Nightmare of Eden</em>
</a>
</li>
</ul>
The following rendered HTML markup is produced by the preceding DoctorWhoLayout
and Episodes
component. Extraneous markup doesn't appear in order to focus on the content provided by the two components involved:
- The H1 "database" heading (
<h1>...</h1>
) in the header (<header>...</header>
), navigation bar (<nav>...</nav>
), and trademark information in the footer (<footer>...</footer>
) come from theDoctorWhoLayout
component. - The H2 "episodes" heading (
<h2>...</h2>
) and episode list (<ul>...</ul>
) come from theEpisodes
component.
<header>
<h1 ...>...</h1>
</header>
<nav>
...
</nav>
<h2>...</h2>
<ul>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
<footer>
...
</footer>
Specifying the layout directly in a component overrides a default layout:
- Set by an
@layout
directive imported from an_Imports.razor
file, as described in the following Apply a layout to a folder of components section. - Set as the app's default layout, as described in the Apply a default layout to an app section later in this article.
Apply a layout to a folder of components
Every folder of an app can optionally contain a template file named _Imports.razor
. The compiler includes the directives specified in the imports file in all of the Razor templates in the same folder and recursively in all of its subfolders. Therefore, an _Imports.razor
file containing @layout DoctorWhoLayout
ensures that all of the components in a folder use the DoctorWhoLayout
component. There's no need to repeatedly add @layout DoctorWhoLayout
to all of the Razor components (.razor
) within the folder and subfolders.
_Imports.razor
:
@layout DoctorWhoLayout
...
The _Imports.razor
file is similar to the _ViewImports.cshtml file for Razor views and pages but applied specifically to Razor component files.
Specifying a layout in _Imports.razor
overrides a layout specified as the router's default app layout, which is described in the following section.
Warning
Do not add a Razor @layout
directive to the root _Imports.razor
file, which results in an infinite loop of layouts. To control the default app layout, specify the layout in the Router component. For more information, see the following Apply a default layout to an app section.
Note
The @layout
Razor directive only applies a layout to routable Razor components with an @page
directive.
Apply a default layout to an app
Specify the default app layout in the Router component's RouteView component. Use the DefaultLayout parameter to set the layout type:
<RouteView RouteData="routeData" DefaultLayout="typeof({LAYOUT})" />
In the preceding example, the {LAYOUT}
placeholder is the layout (for example, DoctorWhoLayout
if the layout file name is DoctorWhoLayout.razor
). You may need to idenfity the layout's namespace depending on the .NET version and type of Blazor app. For more information, see the Make the layout namespace available section.
Specifying the layout as a default layout in the Router component's RouteView is a useful practice because you can override the layout on a per-component or per-folder basis, as described in the preceding sections of this article. We recommend using the Router component to set the app's default layout because it's the most general and flexible approach for using layouts.
Apply a layout to arbitrary content (LayoutView
component)
To set a layout for arbitrary Razor template content, specify the layout with a LayoutView component. You can use a LayoutView in any Razor component. The following example sets a layout component named ErrorLayout
for the MainLayout
component's NotFound template (<NotFound>...</NotFound>
).
<Router ...>
<Found ...>
...
</Found>
<NotFound>
<LayoutView Layout="typeof(ErrorLayout)">
<h1>Page not found</h1>
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
You may need to identity the layout's namespace depending on the .NET version and type of Blazor app. For more information, see the Make the layout namespace available section.
Important
Blazor Web Apps don't use the NotFound parameter (<NotFound>...</NotFound>
markup), but the parameter is supported for backward compatibility to avoid a breaking change in the framework. The server-side ASP.NET Core middleware pipeline processes requests on the server. Use server-side techniques to handle bad requests. For more information, see ASP.NET Core Blazor render modes.
Note
With the release of ASP.NET Core 5.0.1 and for any additional 5.x releases, the Router
component includes the PreferExactMatches
parameter set to @true
. For more information, see Migrate from ASP.NET Core 3.1 to 5.0.
Nested layouts
A component can reference a layout that in turn references another layout. For example, nested layouts are used to create a multi-level menu structures.
The following example shows how to use nested layouts. The Episodes
component shown in the Apply a layout to a component section is the component to display. The component references the DoctorWhoLayout
component.
The following DoctorWhoLayout
component is a modified version of the example shown earlier in this article. The header and footer elements are removed, and the layout references another layout, ProductionsLayout
. The Episodes
component is rendered where @Body
appears in the DoctorWhoLayout
.
DoctorWhoLayout.razor
:
@inherits LayoutComponentBase
@layout ProductionsLayout
<PageTitle>Doctor Who® Database</PageTitle>
<h1>Doctor Who® Database</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
@Body
<div>
@TrademarkMessage
</div>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
@layout ProductionsLayout
<PageTitle>Doctor Who® Database</PageTitle>
<h1>Doctor Who® Database</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
@Body
<div>
@TrademarkMessage
</div>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
@layout ProductionsLayout
<h1>Doctor Who™ Episode Database</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
@Body
<div>
@TrademarkMessage
</div>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout
<h1>Doctor Who™ Episode Database</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
@Body
<div>
@TrademarkMessage
</div>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout
<h1>Doctor Who™ Episode Database</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
@Body
<div>
@TrademarkMessage
</div>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout
<h1>Doctor Who™ Episode Database</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
@Body
<div>
@TrademarkMessage
</div>
@code {
public string TrademarkMessage { get; set; } =
"Doctor Who is a registered trademark of the BBC. " +
"https://www.doctorwho.tv/";
}
The ProductionsLayout
component contains the top-level layout elements, where the header (<header>...</header>
) and footer (<footer>...</footer>
) elements now reside. The DoctorWhoLayout
with the Episodes
component is rendered where @Body
appears.
ProductionsLayout.razor
:
@inherits LayoutComponentBase
<header>
<h1>Productions</h1>
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
@Body
<footer>
Footer of Productions Layout
</footer>
@inherits LayoutComponentBase
<header>
<h1>Productions</h1>
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
@Body
<footer>
Footer of Productions Layout
</footer>
@inherits LayoutComponentBase
<header>
<h1>Productions</h1>
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
@Body
<footer>
Footer of Productions Layout
</footer>
@inherits LayoutComponentBase
<header>
<h1>Productions</h1>
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
@Body
<footer>
Footer of Productions Layout
</footer>
@inherits LayoutComponentBase
<header>
<h1>Productions</h1>
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
@Body
<footer>
Footer of Productions Layout
</footer>
@inherits LayoutComponentBase
<header>
<h1>Productions</h1>
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
@Body
<footer>
Footer of Productions Layout
</footer>
The following rendered HTML markup is produced by the preceding nested layout. Extraneous markup doesn't appear in order to focus on the nested content provided by the three components involved:
- The header (
<header>...</header>
), production navigation bar (<nav>...</nav>
), and footer (<footer>...</footer>
) elements and their content come from theProductionsLayout
component. - The H1 "database" heading (
<h1>...</h1>
), episode navigation bar (<nav>...</nav>
), and trademark information (<div>...</div>
) come from theDoctorWhoLayout
component. - The H2 "episodes" heading (
<h2>...</h2>
) and episode list (<ul>...</ul>
) come from theEpisodes
component.
<header>
...
</header>
<nav>
<a href="main-production-list">Main Production List</a>
<a href="production-search">Search</a>
<a href="new-production">Add Production</a>
</nav>
<h1>...</h1>
<nav>
<a href="main-episode-list">Main Episode List</a>
<a href="episode-search">Search</a>
<a href="new-episode">Add Episode</a>
</nav>
<h2>...</h2>
<ul>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
<div>
...
</div>
<footer>
...
</footer>
Share a Razor Pages layout with integrated components
When routable components are integrated into a Razor Pages app, the app's shared layout can be used with the components. For more information, see Integrate ASP.NET Core Razor components into ASP.NET Core apps.
When routable components are integrated into a Razor Pages app, the app's shared layout can be used with the components. For more information, see Prerender and integrate ASP.NET Core Razor components.
Sections
To control the content in a layout from a child Razor component, see ASP.NET Core Blazor sections.