Description
Background and Motivation
Related to #28182.
There is a need for a feature that will allow customers to change a part of main layout depending on which page they are on. A solution to achieve that exists and was described in #28182 (comment). Similar solution was implemented as part of #10450. https://github.com/dotnet/aspnetcore/tree/main/src/Components/Components/src/Sections these classes are internal.
We want to make them a part of public API (and change a few things for other potential use cases).
Proposed API
SectionOutlet
component that renders content provided by SectionContent
with the same SectionId
public sealed class SectionOutlet : IComponent, IDisposable
{
[Parameter, EditorRequired] public object SectionId { get; set; }
}
public sealed class SectionContent : IComponent, IDisposable
{
[Parameter, EditorRequired] public object SectionId { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; }
{
Usage Examples
Common use case would be to use SectionOutlet
component in MainLayout.razor
and provide the desired content via SectionContent
component in other pages.
This is not the only case. You could use SectionOutlet
SectionContent
to modify a part of parent component depending on which child components are rendered.
Example:
- Add this code into the default template's
MainLayout.razor
:
@code{
internal static object TopbarSection = new();
}
- Add
SectionOutlet
into the default template'sMainLayout.razor
:
<div class="top-row px-4">
<SectionOutlet SectionId="TopbarSection" />
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
- Add
SectionContent
intoCounter.razor
:
<SectionContent SectionId="MainLayout.TopbarSection">
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SectionContent>
You'll get this:
If you don't want to use a static field inMainlayout.razor
you could also use a string as SectionId
:
<SectionOutlet SectionId="@("topbar")" />
In Counter.razor
:
<SectionContent SectionId="@("topbar")">
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SectionContent>
Alternative Designs
The original design with string Name
as an identifier instead of object SectionId
.
public sealed class SectionOutlet : IComponent, IDisposable
{
[Parameter, EditorRequired] public string Name { get; set; }
}
public sealed class SectionContent : IComponent, IDisposable
{
[Parameter, EditorRequired] public string Name { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; }
{
With this design you cannot hide your SectionOutlet
. This is useful when you are developing a library and you don't want any accidental content in the user's app to be rendered in library's component.
Risks
Case when SectionId
is IEquatable<T>
and Equals(object)
, GetHashCode()
not overriden.