In Blazor, rendering is the mechanism that produces HTML from Razor components, which the browser then interprets to present the user interface. For developers working with Blazor, controlling how the final HTML output looks is an essential goal. In this tutorial, you will learn:
An HTML tag comprises 3 parts: the tag name, attributes, and content. Consider this example:
Consider this HTML example:
Here, div
is the tag name, data-my-custom
is the attribute with Ok
as its value, and Hello Blazor School!
is the content.
Since this markup is static HTML, rendering it in Blazor is straightforward. Just provide the same markup to a Razor Component, and Blazor will output the corresponding HTML unchanged.
In HTML, attributes play a big role in describing an HTML element. These attributes can provide data (with data-*
), change its appearance, or be used to scope a CSS class so that the CSS class name can be reused in the app. Building on the basic rendering example, where you rendered a div
with a known attribute (data-my-custom
), Blazor also supports dynamic attribute rendering without prior specification. This is particularly useful when creating a component library, allowing users to attach their own attributes to your elements for downstream processing. Examine this example:
<div @attributes="customAttributes">RenderWithAttribute</div> @code { Dictionary<string, object> customAttributes = new Dictionary<string, object> { { "class", "text-bg-primary" }, { "data-name", "Blazor School" } }; }
Blazor renders this as:
<div class="text-bg-primary" data-name="Blazor School">RenderWithAttribute</div>
In the example, we have a Dictionary<string, object>
as the collection of attributes which are applied to the div
using the @attributes
directive. This approach allows developers to pass 2 or more attributes dynamically to the rendered element.
When something changes in a component, Blazor will render it again. However, not all changes need the UI to be updated. To improve performance in such cases, we can hold the rerendering process and only render when needed. Consider the following code sample:
<label> Give me a string <input type="text" @bind-value="Text" @bind-value:event="oninput" /> </label> <div>Your string: @Text</div> @code { public string Text { get; set; } = ""; protected override bool ShouldRender() { return Text.Length > 3; } }
In this example, we have a textbox to capture user input and a div
reflects the entered data. To improve efficiency, ShouldRender
is overridden to restrict updates where the input is 3 or fewer letters.
In Blazor, a component can render itself recursively to build complex, hierarchical displays, such as a tree structure, which is ideal for nested data like a JSON object. Take this data structure:
public record TreeNodeData(string Name, List<TreeNodeData> Children);
TreeNode.razor
component can be designed to render this tree recursively:<div style="padding-left: @(Level*10)px">Node: @Node.Name</div> @foreach (var child in Node.Children) { <TreeNode Node="child" Level="Level + 1" /> } @code { [Parameter] public TreeNodeData Node { get; set; } = null!; [Parameter] public int Level { get; set; } = 0; }
To use it in another component, simply pass a list of nodes:
@foreach (var node in Nodes) { <TreeNode Node="node" /> } @code { public List<TreeNodeData> Nodes { get; set; } = new() { new("Root", new() { new("Child1", new()), new("Child2", new()) }) }; }
In this example, the TreeNode
component renders itself for each child, indenting based on Level to form a tree-like UI.
Blazor manages the creation and updating of HTML elements, including their inner content and attributes, within its rendering system. A frequent error is attempting to modify Blazor-managed elements with JavaScript—or vice versa. Examine this example:
<div id="TestElement">@BlazorManagedValue</div> <button type="button" @onclick='_ => BlazorManagedValue = "Updated by Blazor"'>Update Value with Blazor</button> <button type="button" onclick="updateAttribute()">Update Value with JavaScript</button> @code { public string BlazorManagedValue { get; set; } = "Initiated by Blazor"; } <script> function updateAttribute() { document.getElementById("TestElement").innerText = "Updated by JavaScript"; } </script>
In this example, the div
's content is initially set by Blazor. Clicking the Blazor button updates it via Blazor's rendering, which works perfectly. However, clicking the JavaScript button alters the DOM directly, making updating with Blazor impossible afterwards.