Introduction To Templated Components In Blazor

Blazor has components at the core part. It uses the combination of Razor, HTML and C# code as a component. A component is the base element of the Blazor application, i.e., every page is considered as a component in Blazor. Blazor use the Razor template engine that generate HTML and served to web browsers. We can mix HTML and C# syntax in the Razor template and Razor engine will compiled Razor template and generate the HTML.

Introduction
 
Just like modern client frameworks, such as Angular, Blazor also has components at its core. It uses the combination of Razor, HTML, and C# code as a component. A component is the base element of the Blazor application, i.e., every page is considered as a component in Blazor. Blazor uses the Razor template engine that generates HTML and serves to the web browsers. We can mix HTML and C# syntax in the Razor templates and Razor engine then compiles the Razor templates to generate the HTML.
 
Blazor (version 0.6.0) supports the templated component. It is a component which accepts one or more UI templates as parameters and these parameters can be used for component rendering. It allows us to write high-level reusable components. Using templated components, we can write a generic and more reusable component.
 
We can create the templated component by using one or more component parameters of type RenderFragment or RenderFragment<T>. The RenderFragment is a part of UI which is rendered by the component. It may have parameters that are used during the rendering of the component or while the RenderFragment is invoked.
 
Example
 
A ListView component allows us to define a template for rendering each item of the list. Similarly, we can create a template for the header, footer, and each row of a GridView component.
 
In the following example, I have created a templated component for the table (grid). Here, I have three fragments of the templated component - Header, Rows, and Footer. All these fragments are generated using the parameters. The parameters have the actual HTML and context data that need to be replaced during the generation of the HTML.
 
GridTemplate.cshtml
  1. @typeparam TItem  
  2.   
  3. <table border="1">  
  4.     <thead>  
  5.         <tr>@Header</tr>  
  6.     </thead>  
  7.     <tbody>  
  8.         @foreach (var item in Items)  
  9.         {  
  10.             <tr>@Row(item)</tr>  
  11.         }  
  12.     </tbody>  
  13.     <tfoot>  
  14.         <tr>@Footer</tr>  
  15.     </tfoot>  
  16. </table>  
  17.   
  18. @functions {  
  19.     [Parameter]  
  20.     RenderFragment Header { get; set; }  
  21.   
  22.     [Parameter]  
  23.     RenderFragment<TItem> Row { get; set; }  
  24.   
  25.     [Parameter]  
  26.     RenderFragment Footer { get; set; }  
  27.   
  28.     [Parameter]  
  29.     IReadOnlyList<TItem> Items { get; set; }  
  30. }  
When we use a templated component in Blazor component, we can specify the template parameters using the child elements, however, the name of the template parameters must match with that of the child elements.
 
We can access the data that is passed by the template component (of type RenderFragment<T>) using "context" property.
 
example1.cshtml
  1. @page "/"  
  2.   
  3. @inject HttpClient Http  
  4. @using TemplatedComponents.Model  
  5. @if (data == null)  
  6. {  
  7. <p><em>Loading...Test</em></p>  
  8. }  
  9. else  
  10. {  
  11. <GridTemplate Items="@data">  
  12.     <Header>  
  13.         <th>ID</th>  
  14.         <th>Name</th>  
  15.         <th>Description</th>  
  16.     </Header>  
  17.     <Row>  
  18.         <td>@context.Id</td>  
  19.         <td>@context.Name</td>  
  20.         <td>@context.Description</td>  
  21.     </Row>  
  22.     <Footer>  
  23.         <td colspan="3">This is a grid footer</td>  
  24.     </Footer>  
  25. </GridTemplate>  
  26. }  
  27. @functions {  
  28.     MyItems[] data;  
  29.   
  30.     protected override async Task OnInitAsync()  
  31.     {  
  32.            data = await Http.GetJsonAsync<MyItems[]>("sample-data/test.json");  
  33.     }  
  34. }  
Templated components in Blazor 
 
The "context" parameter is the implicit parameter, however, we can change the parameter using the "Context" attribute on the templated component.
 
example1.cshtml
  1. <GridTemplate Items="@data">  
  2.     .....  
  3.     ....  
  4.     <Row Context="test">  
  5.         <td>@test.Id</td>  
  6.         <td>@test.Name</td>  
  7.         <td>@test.Description</td>  
  8.     </Row>  
  9.     ....  
  10.     ....  
  11. </GridTemplate>  
Alternatively, we can specify this attribute on the component element. So, this attribute applies to all specified template parameters.
 
example1.cshtml
  1. <GridTemplate Items="@data" Context="test">  
  2.     ....  
  3.     ....  
  4. </GridTemplate>  
The templated components are always generically typed. In the above example, the templated component can render as IEnumerable<T>. The directive @typeparam is used to specify type parameters.
 
GenericComponent.cshtml
  1. @typeparam TItem  
  2.   
  3. @foreach (var item in Items)  
  4. {  
  5.     @ItemTemplate(item)  
  6. }  
  7.   
  8. @functions {  
  9.     [Parameter]   
  10.     RenderFragment<TItem> ItemTemplate { get; set; }  
  11.     [Parameter]   
  12.     IReadOnlyList<TItem> Items { get; set; }  
  13. }  
The parameter type can be identified when using generic-typed components. We can also explicitly specify a type using the attribute. Again, the name of the parameter must match.
 
Example2.cshtml
  1. @page "/example2"  
  2.   
  3. @inject HttpClient Http  
  4. @using TemplatedComponents.Model;  
  5. @if (data == null)  
  6. {  
  7.     <p><em>Loading...Test</em></p>  
  8. }  
  9. else  
  10. {  
  11.     <ui>  
  12.         <GenericComponent Items="@data" TItem="MyItems">  
  13.             <ItemTemplate>  
  14.                 <li>  
  15.                     @context.Name  
  16.                 </li>  
  17.             </ItemTemplate>  
  18.         </GenericComponent>  
  19.     </ui>  
  20. }  
  21. @functions {  
  22.     MyItems[] data;  
  23.   
  24.     protected override async Task OnInitAsync()  
  25.     {  
  26.         data = await Http.GetJsonAsync<MyItems[]>("sample-data/test.json");  
  27.     }  
  28. }  
Templated components in Blazor
 
Razor templates
 
We can also define the RenderFragment using Razor Template Syntax. We can use the Razor template to define RenderFragment and RenderFragment<T> values. The templated components can be rendered either using a Razor template with an argument or directly.
 
Example3.cshtml 
  1. @page "/example3"  
  2.   
  3. @inject HttpClient Http  
  4. @using TemplatedComponents.Model;  
  5.   
  6. @{  
  7.     RenderFragment template = @<p>Hello C# Corner Reader!</p>;  
  8.     RenderFragment<MyItems> ItemTemplate = (item) => @<li>@item.Name.</li>;  
  9. }  
  10.   
  11. @if (data == null)  
  12. {  
  13.     <p><em>Loading...Test</em></p>  
  14. }  
  15. else  
  16. {  
  17.   
  18. @template  
  19. <ul>  
  20.     @foreach (var item in data)  
  21.     {  
  22.         @ItemTemplate(item)  
  23.     }  
  24. </ul>  
  25. }  
  26.   
  27.   
  28.   
  29. @functions {  
  30.     MyItems[] data;  
  31.   
  32.     protected override async Task OnInitAsync()  
  33.     {  
  34.         data = await Http.GetJsonAsync<MyItems[]>("sample-data/test.json");  
  35.     }  
  36. }  
Templated components in Blazor 
 
Summary
 
The templated components are supported by Blazor. It is a component which accepts one or more UI templates as parameters and these parameters can be used for component rendering. It allows us to write high-level reusable components. Using a templated component, we can write the generic or more reusable component.
 
You can view or download the source code from the GitHub link here.