Skip to content

Blazor layout sections #28660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions aspnetcore/blazor/components/layouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,14 @@ The following rendered HTML markup is produced by the preceding nested layout. E

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 <xref:blazor/components/prerendering-and-integration>.

:::moniker range=">= aspnetcore-8.0"

## Sections

To control the content in a layout from a child Razor component, see <xref:blazor/components/sections>.

:::moniker-end

## Additional resources

* <xref:mvc/views/layout>
Expand Down
80 changes: 80 additions & 0 deletions aspnetcore/blazor/components/sections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: ASP.NET Core Blazor sections
author: guardrex
description: Learn how to to control the content in a Razor component from a child Razor component.
monikerRange: '>= aspnetcore-8.0'
ms.author: riande
ms.custom: mvc
ms.date: 04/18/2023
uid: blazor/components/sections
---
# ASP.NET Core Blazor sections

To control the content in a Razor component from a child Razor component, Blazor supports *sections* using the following built-in components:

* `SectionOutlet`: Renders content provided by `SectionContent` components with matching `SectionName` or `SectionId` arguments. Two or more `SectionOutlet` components can't have the the same `SectionName` or `SectionId`.

* `SectionContent`: Provides content as a <xref:Microsoft.AspNetCore.Components.RenderFragment> to `SectionOutlet` components with a matching `SectionName` or `SectionId`. If several `SectionContent` components have the same `SectionName` or `SectionId`, the matching `SectionOutlet` component renders the content of the last rendered `SectionContent`.

Sections can be used in both [layouts](xref:blazor/components/layouts) and across nested parent-child components.

Although the argument passed to `SectionName` can use any type of casing, the documentation adopts kebab casing (for example, `top-bar`), which is a common casing choice for HTML element IDs. `SectionId` receives a static `object` field, and we always recommend Pascal casing for C# field names (for example, `TopbarSection`).

In the following example, the app's main layout component implements an increment counter button for the app's `Counter` component.

Add the namespace for sections to the `_Imports.razor` file:

```razor
@using Microsoft.AspNetCore.Components.Sections
```

In the `MainLayout` component (`Shared/MainLayout.razor`), place a `SectionOutlet` component and pass a string to the `SectionName` parameter to indicate the section's name. The following example uses the section name `top-bar`:

```razor
<SectionOutlet SectionName="top-bar" />
```

In the `Counter` component (`Pages/Counter.razor`), create a `SectionContent` component and pass the matching string (`top-bar`) to its `SectionName` parameter:

```razor
<SectionContent SectionName="top-bar">
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SectionContent>
```

When the `Counter` component is accessed at `/counter`, the `MainLayout` component renders the increment count button from the `Counter` component where the `SectionOutlet` component is placed. When any other component is accessed, the increment count button isn't rendered.

Instead of using a named section, you can pass a static `object` with the `SectionId` parameter to identify the section. The following example also implements an increment counter button for the app's `Counter` component in the app's main layout.

If you don't want other `SectionContent` components to accidentally match the name of a `SectionOutlet`, pass an object `SectionId` parameter to identify the section. This can be useful when designing a [Razor class library (RCL)](xref:blazor/components/class-libraries). When a `SectionOutlet` in the RCL uses an object reference with `SectionId` and the consumer places a `SectionContent` component with a matching `SectionId` object, an accidental match by name isn't possible when consumers of the RCL implement other `SectionContent` components.

The following example also implements an increment counter button for the app's `Counter` component in the app's main layout, using an object reference instead of a section name.

Add a `TopbarSection` static `object` to the `MainLayout` component in an `@code` block:

```razor
@code {
internal static object TopbarSection = new();
}
```

In the `MainLayout` component's Razor markup, place a `SectionOutlet` component and pass `TopbarSection` to the `SectionId` parameter to indicate the section:

```razor
<SectionOutlet SectionId="TopbarSection" />
```

Add a `SectionContent` component to the app's `Counter` component that renders an increment count button. Use the `MainLayout` component's `TopbarSection` section static `object` as the `SectionId` (`MainLayout.TopbarSection`).

In `Pages/Counter.razor`:

```razor
<SectionContent SectionId="MainLayout.TopbarSection">
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SectionContent>
```

When the `Counter` component is accessed, the `MainLayout` component renders the increment count button where the `SectionOutlet` component is placed.

> [!NOTE]
> `SectionOutlet` and `SectionContent` components can only set either `SectionId` or `SectionName`, not both.
2 changes: 2 additions & 0 deletions aspnetcore/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ items:
uid: blazor/components/index
- name: Layouts
uid: blazor/components/layouts
- name: Sections
uid: blazor/components/sections
- name: Control <head> content
uid: blazor/components/control-head-content
- name: Cascading values and parameters
Expand Down