Child Components via ChildContent
Components can set the content of another Component.
Creating
Define a ChildContent
component parameter of type RenderFragment
:Shared/SomeChild.razor
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
The Component that uses the child component provides the content that it renders:
@page "/render-fragment-parent"
<h1>Render child content</h1>
<SomeChild>
Content of the child component is supplied
by the parent component.
</SomeChild>
Considerations
Event Callbacks
Event callbacks are not supported in RenderFragment
.
Child components and for
loops
Rendering components inside a for
loop require a local index variable if that loop variable is used to render the child component’s content:
<h1>Three children with an index variable</h1>
@for (int c = 0; c < 3; c++)
{
var current = c;
<SomeChild>
Count: @current
</SomeChild>
}
Alternatively, use a foreach
loop and Enumerable.Range
:
@foreach (var c in Enumerable.Range(0,3))
{
<SomeChild>
Count: @c
</SomeChild>
}
RenderFragment
RenderFragment
is a built-in type that represents a fragment of UI content. It allows one Component to set the content of another.
ProfilePicture.razor.cs
public partial class ProfilePicture
{
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
ProfilePicture.razor
<div class="profile-picture">
@ChildContent
</div>
When this Component is used, the content of the Component (the value between the open/close tags) is pushed to the ChildContent
property, which is then rendered in HTML @ChildContent
:
SomeComponent.razor
<ProfilePicture>
![](./images/pic.jpg)
</ProfilePicture>
Limitations
- The property receiving the
RenderFragment
content must be namedChildContent
. - Event callbacks are not supported with
RenderFragment
.
Templated Components
Components that receive one or more UI templates as parameters. These parameters can be used as rendering logic in the Component. This allows you to create higher-level components that can be reused, like:
- A table component that allows users to specify templates for the table’s headers, rows and footer.
- A list component that allows users to specify a template for rendering items in a list.
Creating
Create a templated component by specifying one or more parameters of type RenderFragment
or RenderFragment<TValue>
. Templated components are often generically typed.
A TableTemplate
component is created:
Shared/TableTemplate.razor
@typeparam TItem
@using System.Diagnostics.CodeAnalysis
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
if (RowTemplate is not null)
{
<tr>@RowTemplate(item)</tr>
}
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter]
public RenderFragment<TItem>? RowTemplate { get; set; }
[Parameter, AllowNull]
public IReadOnlyList<TItem> Items { get; set; }
}
Here, the templated component is used. The template parameters are specified using child elements that match the name of the parameters:
Pages/Pets1.razor
@page "/pets1"
<h1>Pets</h1>
<!-- TableTemplate.Items expects a IReadOnlyList<T>, so we supply a List<Pet> here.
The TableTemplate element's Context attribute is set to the content parameter name for implicit
child content. It applies to all RenderFragment<TValue> template parameters: -->
<TableTemplate Items="pets" Context="pet">
<!-- This child element matches the name of the TableTemplate component's TableHeader parameter.
TableTemplate.TableHeader expects a RenderFragment, so we supply one: -->
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<!-- Since Context="pet" is defined as an attribute on the TableTemplate element, and since
RowTemplate expects a RenderFragment<ITem>, the parameter name "pet" is used: -->
<RowTemplate>
<td>@pet.PetId</td>
<td>@pet.Name</td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
The Component’s generic type is inferred whenever possible, but can also be set explicitly:
<!-- ... -->
<TableTemplate Items="pets" TItem="Pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td>@context.PetId</td>
<td>@context.Name</td>
</RowTemplate>
</TableTemplate>
<!-- ... -->
Rather than setting the Context
attribute on the component’s element, we can set it on the child element to set the parameter name:
<!-- ... -->
<RowTemplate Context="pet">
<td>@pet.PetId</td>
<td>@pet.Name</td>
</RowTemplate>
<!-- ... -->
Or, component arguments of type RenderFragment<TValue>
has an implicit context
parameter that can be used:
<!-- ... -->
<RowTemplate>
<td>@context.PetId</td>
<td>@context.Name</td>
</RowTemplate>
<!-- ... -->