diff --git a/aspnetcore/blazor/components/built-in-components.md b/aspnetcore/blazor/components/built-in-components.md index 05470eb88d2e..c86fec34c08c 100644 --- a/aspnetcore/blazor/components/built-in-components.md +++ b/aspnetcore/blazor/components/built-in-components.md @@ -37,7 +37,7 @@ The following built-in Razor components are provided by the Blazor framework. Fo * [`InputSelect`](xref:blazor/forms/input-components) * [`InputText`](xref:blazor/forms/input-components) * [`InputTextArea`](xref:blazor/forms/input-components) -* [`LayoutComponentBase`](xref:blazor/components/layouts#layout-components) +* [`LayoutComponentBase`](xref:blazor/components/layouts#create-a-layout-component) * [`LayoutView`](xref:blazor/components/layouts#apply-a-layout-to-arbitrary-content-layoutview-component) * [`NavigationLock`](xref:blazor/fundamentals/routing#handleprevent-location-changes) * [`NavLink`](xref:blazor/fundamentals/routing#navlink-component) @@ -77,7 +77,7 @@ The following built-in Razor components are provided by the Blazor framework. Fo * [`InputSelect`](xref:blazor/forms/input-components) * [`InputText`](xref:blazor/forms/input-components) * [`InputTextArea`](xref:blazor/forms/input-components) -* [`LayoutComponentBase`](xref:blazor/components/layouts#layout-components) +* [`LayoutComponentBase`](xref:blazor/components/layouts#create-a-layout-component) * [`LayoutView`](xref:blazor/components/layouts#apply-a-layout-to-arbitrary-content-layoutview-component) * [`NavigationLock`](xref:blazor/fundamentals/routing#handleprevent-location-changes) * [`NavLink`](xref:blazor/fundamentals/routing#navlink-component) @@ -115,7 +115,7 @@ The following built-in Razor components are provided by the Blazor framework. Fo * [`InputSelect`](xref:blazor/forms/input-components) * [`InputText`](xref:blazor/forms/input-components) * [`InputTextArea`](xref:blazor/forms/input-components) -* [`LayoutComponentBase`](xref:blazor/components/layouts#layout-components) +* [`LayoutComponentBase`](xref:blazor/components/layouts#create-a-layout-component) * [`LayoutView`](xref:blazor/components/layouts#apply-a-layout-to-arbitrary-content-layoutview-component) * [`NavigationLock`](xref:blazor/fundamentals/routing#handleprevent-location-changes) * [`NavLink`](xref:blazor/fundamentals/routing#navlink-component) @@ -149,7 +149,7 @@ The following built-in Razor components are provided by the Blazor framework. Fo * [`InputSelect`](xref:blazor/forms/input-components) * [`InputText`](xref:blazor/forms/input-components) * [`InputTextArea`](xref:blazor/forms/input-components) -* [`LayoutComponentBase`](xref:blazor/components/layouts#layout-components) +* [`LayoutComponentBase`](xref:blazor/components/layouts#create-a-layout-component) * [`LayoutView`](xref:blazor/components/layouts#apply-a-layout-to-arbitrary-content-layoutview-component) * [`NavLink`](xref:blazor/fundamentals/routing#navlink-component) * [`OwningComponentBase`](xref:fundamentals/dependency-injection#utility-base-component-classes-to-manage-a-di-scope) @@ -177,7 +177,7 @@ The following built-in Razor components are provided by the Blazor framework. Fo * [`InputSelect`](xref:blazor/forms/input-components) * [`InputText`](xref:blazor/forms/input-components) * [`InputTextArea`](xref:blazor/forms/input-components) -* [`LayoutComponentBase`](xref:blazor/components/layouts#layout-components) +* [`LayoutComponentBase`](xref:blazor/components/layouts#create-a-layout-component) * [`LayoutView`](xref:blazor/components/layouts#apply-a-layout-to-arbitrary-content-layoutview-component) * [`NavLink`](xref:blazor/fundamentals/routing#navlink-component) * [`OwningComponentBase`](xref:fundamentals/dependency-injection#utility-base-component-classes-to-manage-a-di-scope) @@ -203,7 +203,7 @@ The following built-in Razor components are provided by the Blazor framework. Fo * [`InputSelect`](xref:blazor/forms/input-components) * [`InputText`](xref:blazor/forms/input-components) * [`InputTextArea`](xref:blazor/forms/input-components) -* [`LayoutComponentBase`](xref:blazor/components/layouts#layout-components) +* [`LayoutComponentBase`](xref:blazor/components/layouts#create-a-layout-component) * [`LayoutView`](xref:blazor/components/layouts#apply-a-layout-to-arbitrary-content-layoutview-component) * [`NavLink`](xref:blazor/fundamentals/routing#navlink-component) * [`OwningComponentBase`](xref:fundamentals/dependency-injection#utility-base-component-classes-to-manage-a-di-scope) diff --git a/aspnetcore/blazor/components/layouts.md b/aspnetcore/blazor/components/layouts.md index 3e39a46aed2b..1841b157ac78 100644 --- a/aspnetcore/blazor/components/layouts.md +++ b/aspnetcore/blazor/components/layouts.md @@ -20,9 +20,7 @@ Some app elements, such as menus, copyright messages, and company logos, are usu A Blazor layout is a Razor component that shares markup with components that reference it. Layouts can use [data binding](xref:blazor/components/data-binding), [dependency injection](xref:blazor/fundamentals/dependency-injection), and other features of components. -## Layout components - -### Create a layout component +## Create a layout component To create a layout component: @@ -73,7 +71,7 @@ The following `DoctorWhoLayout` component shows the Razor template of a layout c :::moniker-end -### `MainLayout` component +## `MainLayout` component In an app created from a [Blazor project template](xref:blazor/project-structure), the `MainLayout` component is the app's [default layout](#apply-a-default-layout-to-an-app). Blazor's layout adopts the [:::no-loc text="Flexbox"::: layout model](https://developer.mozilla.org/docs/Glossary/Flexbox) ([W3C specification](https://www.w3.org/TR/css-flexbox-1/)). @@ -94,6 +92,86 @@ In an app created from a [Blazor project template](xref:blazor/project-structure :::moniker-end +:::moniker range=">= aspnetcore-8.0" + + + +## Statically-rendered layout components + +When a Blazor Web App adopts per-page/component rendering (the `Routes` component doesn't specify an interactive render mode), layout components are rendered statically on the server. Applying an interactive render mode directly to a layout isn't supported because Blazor doesn't support serializing a (`@Body` in this case) as a root component parameter. For example, placing `@rendermode InteractiveServer` at the top of the `MainLayout` component results in the following runtime exception: + +> :::no-loc text="System.InvalidOperationException: Cannot pass the parameter 'Body' to component 'MainLayout' with rendermode 'InteractiveServerRenderMode'. This is because the parameter is of the delegate type 'Microsoft.AspNetCore.Components.RenderFragment', which is arbitrary code and cannot be serialized."::: + +This applies to any layout component that inherits from in an app that adopts per-page/component rendering. + +This scenario might be addressed in a future release of Blazor. For more information, see [[Blazor] Support serializing render fragments from SSR (`dotnet/aspnetcore` #52768)](https://github.com/dotnet/aspnetcore/issues/52768). In the meantime, you can adopt the following approach in a Blazor Web App that adopts per-page/component rendering. + +Create a wrapper component that's capable of interactivity. In the following example, a wrapper component contains a [Blazor section](xref:blazor/components/sections) that can receive content from a child component. + +In the `_Imports.razor` file, add an [`@using`](xref:mvc/views/razor#using) directive for sections (): + +```razor +@using Microsoft.AspNetCore.Components.Sections +``` + +Create the following interactive wrapper component in the `Pages` folder. + +`Pages/InteractiveWrapper.razor`: + +```razor +@rendermode InteractiveServer + +
+ +
+ +@ChildContent + +@code { + [Parameter] + public RenderFragment? ChildContent { get; set; } +} +``` + +The `Counter` component can use the wrapper component and set interactive section content. In the following example, a counter button is placed in the section. + +`Pages/Counter.razor`: + +```razor +@page "/counter" +@rendermode InteractiveServer + + + + + + + + Counter + +

Counter

+ +

Current count: @currentCount

+ + + +
+ +@code { + private int currentCount = 0; + + private void IncrementCount() + { + currentCount++; + } +} +``` + +Other components around the app can also wrap content in the `InteractiveWrapper` component and set interactive section content. + +:::moniker-end + ## Apply a layout ### Make the layout namespace available @@ -220,7 +298,7 @@ Specify the default app layout in the ``` -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](#make-the-layout-namespace-available) section. +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 identify the layout's namespace depending on the .NET version and type of Blazor app. For more information, see the [Make the layout namespace available](#make-the-layout-namespace-available) section. Specifying the layout as a default layout in the component's 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 component to set the app's default layout because it's the most general and flexible approach for using layouts. diff --git a/aspnetcore/blazor/components/render-modes.md b/aspnetcore/blazor/components/render-modes.md index 38d23bf0364a..c4daeef0cc5e 100644 --- a/aspnetcore/blazor/components/render-modes.md +++ b/aspnetcore/blazor/components/render-modes.md @@ -576,6 +576,11 @@ Non-serializable component parameters, such as child content or a render fragmen > :::no-loc text="System.InvalidOperationException: Cannot pass the parameter 'ChildContent' to component 'SharedMessage' with rendermode 'InteractiveServerRenderMode'. This is because the parameter is of the delegate type 'Microsoft.AspNetCore.Components.RenderFragment', which is arbitrary code and cannot be serialized."::: + + +The same thing happens if you attempt to adopt interactive rendering in a layout that inherits from , such as the app's `MainLayout` component, in an app that adopts per-page/component rendering. For more information, see . + To circumvent the preceding limitation, wrap the child component in another component that doesn't have the parameter. This is the approach taken in the Blazor Web App project template with the `Routes` component (`Components/Routes.razor`) to wrap the component. `WrapperComponent.razor`: