Creating components with customizable content
Creating components with customizable content in Blazor applications is another level in building flexible and reusable UI elements. This approach allows you to design functional components that can be adapted to various content needs and data types. We’ll utilize the RenderFragment
feature to address it. The RenderFragment
feature represents a segment of UI content. It allows components to accept arbitrary HTML markup as a parameter. That’s how you can achieve higher flexibility. You can repurpose a single component structure with different content, enhancing the modularity and reusability of your code base.
Let’s create a Ticket
component with a customizable display of ticket details while keeping a fixed button so that you can add the ticket to a cart.
Getting ready
Before you start implementing a component with customizable content, do the following:
- Create a
Recipe07
directory – this will be your working directory - Copy the
Chapter01
/Data
directory, which contains theSamples
andTicketViewModel
objects required for this recipe, next to the working directory
How to do it...
Follow these steps to build a component with customizable content:
- Create a new
Ticket
component. We’ll use this to display individual ticket details. - In the
@code
block ofTicket
, add theId
andChildContent
parameters and anAdd()
placeholder method that simply writes a console message displaying the ID of the ticket that was added to the cart:@code { [Parameter, EditorRequired] public Guid Id { get; set; } [Parameter, EditorRequired] public RenderFragment ChildContent { get; set; } public void Add() => Console.WriteLine($"Ticket {Id} added!"); }
- As the
Ticket
markup, render theChildContent
value and a button to trigger theAdd()
method:<div class="ticket"> <div class="ticket-info">@ChildContent</div> <div class="ticket-actions"> <button @onclick="@Add">Add to cart</button> </div> </div>
- Create a routable
Offer
component that renders inInteractiveWebAssembly
mode. Add a@using
directive so that theSamples
object can be referenced:@page "/ch01r07" @using BlazorCookbook.App.Client.Chapters.Chapter01.Data @rendermode InteractiveWebAssembly
- As markup of the
Offer
component, while leveraging theTicket
component, render aSamples.Adult
ticket tariff and price and aSamples.FreeAdmission
ticket with just a tariff name since it’s free to do so:<Ticket Id="@Samples.Adult.Id"> @Samples.Adult.Tariff (@Samples.Adult.Price) </Ticket> <Ticket Id="@Samples.FreeAdmission.Id"> <div class="free-ticket"> @Samples.FreeAdmission.Tariff </div> </Ticket>
How it works...
In step 1, we created a new Ticket
component and implemented its @code
block in step 2. Then, we declared a set of required parameters – Id
to add a ticket to the cart and ChildContent
, which is of the RenderFragment
type, to hold the custom markup for a Ticket
instance. We leveraged the EditorRequired
attribute and made both parameters required. In step 3, we implemented the Ticket
markup. We embedded the ChildContent
value to render ticket details by placing it the same as any other parameter. We also added a button that allows the user to add a ticket to the cart by leveraging the Add()
method.
In step 4, we created an Offer
component. We utilized the @page
directive to make it routable and declared it so that it rendered in the InteractiveWebAssembly
mode. On top of that, we added a @using
directive with the namespace of the Samples
object so that we could reference it within the Offer
component (the namespace can vary depending on the structure and name of your solution). In step 5, we implemented the Offer
markup and saw the RenderFragment
object in action. For an adult ticket with a price tag, we rendered both its tariff and price. For the free admission ticket, we chose to render only the tariff name. Blazor will inject the custom markup in place of the ChildContent
parameter, within the Ticket
component, while retaining and reusing the interactive button implementation, regardless of the customized content.
There’s more...
You can use a RenderFragment
object to encapsulate common parts of your components. The testing and maintainability of your code will skyrocket. Another reason to leverage them is that a static RenderFragment
instance positively impacts performance.
You might have noticed that when a RenderFragment
parameter is named ChildContent
, the compiler automatically recognizes and assigns its value. You can still opt to declare <ChildContent>
</ChildContent>
explicitly but there’s no need to complicate your code.
However, you might encounter scenarios where you need more than one customizable section within a component. Fortunately, Blazor allows you to have multiple RenderFragment
parameters. To implement that, you must explicitly declare both RenderFragment
values using markup element syntax within your component. This approach enables even higher modularity and adaptability of your UI. For instance, you could have Details
and Actions
content to structure your component with multiple customizable areas. You can see that in the following code blocks.
Here’s the Ticket
component, which allows us to customize the Details
and Actions
areas:
<div class="ticket"> <div class="ticket-info">@Details</div> <div class="ticket-actions">@Actions</div> </div> @code { [Parameter, EditorRequired] public RenderFragment Details { get; set; } [Parameter, EditorRequired] public RenderFragment Actions { get; set; } }
Here’s the Ticket
component in action, with customized Details
and Actions
areas:
<Ticket> <Details> @Samples.Adult.Tariff (@Samples.Adult.Price) </Details> <Actions> <button @onclick="@(() => Add(Samples.Adult.Id))"> Add to cart </button> </Actions> </Ticket>