Inject content into your Blazor components with typed Render Fragments

October 6, 2022 · 3 minute read · Tags: blazor

I’ve been doing some more work on the new courseware for https://practicaldotnet.io this week and ran into an interesting use case for Blazor’s Render Fragments.

The application is split up into a couple of different areas.

  • Course content (lessons, videos, that sort of thing)
  • Pretty much everything else (member pages, landing pages, integration with payment providers etc.)

The course content part of the app (called LearnUI) is entirely separate from the rest of the site, in its own Razor Class Library.

Here’s how the main Blazor app then consumes/displays this LearnUI.

@page "/course/{course}/{*slug}"

<CourseContent Course="@Course" Slug="@Slug" OnNodeSelected="@NodeSelected">
</CourseContent>

With this, the main “host” app handles routing, then defers to the CourseContent component (from the Razor Class Library) to actually render something on screen.

As with everything, there are benefits and trade-offs to be considered by having these parts of the UI in separate places but overall I find this logical separation forces me to think a bit more carefully before throwing in markup and logic.

Unlock this course!

But what if we need/want to render content within LearnUI which it doesn’t own?

For example, if someone doesn’t have access to a course, and attempts to view any part of the course, show them an unlock screen, with buttons to go ahead and purchase the course.

That unlock markup and logic doesn’t belong in LearnUI (LearnUI doesn’t have any logic/knowledge of online payments or course prices), so we’d need a way to inject that UI in, and have it shown in place of the course content.

Enter the humble (but extremely useful) RenderFragment

Blazor components can accept one or more RenderFragment parameters, and they mostly do what you would expect; they enable your components to receive a fragment of UI which they can then choose to render.

So, we can make the CourseContent component accept a RenderFragment called LockedUI and render that if the course is locked (the user doesn’t have access).

CourseContent Markup

@if (locked) {
    @LockedUI
} else {
    @page.Content
}

CourseContent @Code

@code {

    private bool locked;

    [Parameter]
    public RenderFragment LockedUI { get; set; }

    ...        
}

Then, in the consuming page/component, we can define some content to be shown for this LockedUI:

<CourseContent Course="@Course" Slug="@Slug" OnNodeSelected="@NodeSelected">
    <LockedUI>
        <p>Unlock this course now!</p>
    </LockedUI>
</CourseContent>

Pass data via the Render Fragment

So far so good, but what if we want to show some more detail about the course that’s locked.

For example, we may want this LockedUI fragment to show the course name, or details about how many lessons are included.

<CourseContent Course="@Course" Slug="@Slug" OnNodeSelected="@NodeSelected">
    <LockedUI>
        <p>Unlock {course name here} now!</p>
    </LockedUI>
</CourseContent>

It feels like that information should come from LearnUI as it has the responsibility for retrieving and showing course contents, but how can we tap into that when providing UI for the LockedUI Render Fragment.

The answer is to get CourseContent to expose those details.

We can modify the RenderFragment parameter to be strongly typed, and pass an object “back” when we render it.

@if (locked) {
    @LockedUI(course)
}

@code {

    CourseDetails course;

    [Parameter]
    public RenderFragment<CourseDetails> LockedUI { get; set; }

}

In the consuming app, we can access this data via @context.

<CourseContent Course="@Course" Slug="@Slug" OnNodeSelected="@NodeSelected">
    <LockedUI>
        <h3>Unlock @context.Name</h3>
        <p>Includes @context.Curriculum.LessonCount() Lessons</p>
    </LockedUI>
</CourseContent>

With that, our consuming app can render the CourseContent component, provide UI to render if the lesson is locked, and easily display any context (data) that the CourseContent component exposes via the LockedUI RenderFragment.

In Summary

You can inject UI into a component using Render Fragments, effectively making a component adaptable, or customisable, in different use cases.

Sometimes you’ll want your UI to reference data from the component which defines the Render Fragment. If so you can make the Render Fragment strongly typed and pass data into it at the point of rendering.

Join the Practical ASP.NET Newsletter

Ship better Blazor apps, faster. One practical tip every Tuesday.

I respect your email privacy. Unsubscribe with one click.

    Next up

    Preventing double clicks in Blazor components
    Guard against duplicate events in your Blazor app
    Avoiding interactivity with Blazor?
    Sometimes a little HTML and CSS is all you need
    How to upload a file with Blazor SSR in .NET 8?
    How to handle file uploads without using an interactive render mode?