Using raw html with isolated CSS in Blazor
In a project I had to create something similar to a syntax highlighter for a Blazor application. The code takes a string and highlights some parts of it. So, the idea is to create a component which outputs a raw html fragment that uses <span class="style-1">text</span>
to colorize some parts of the string. Also, it should use CSS isolation as the style is specific to the component.
I've already written about these 2 subjects independently. In this post we'll see how to use them together!
I've created a component named Highlighter.razor
and its scoped CSS Highlighter.razor.css
:
The CSS is very simple:
.style-0 { background-color: darkgrey; }
.style-1 { background-color: orange; }
.style-2 { background-color: chartreuse; }
The component takes a string and wrap each character into a <span>
with the class style-xxx
from the CSS file:
@highlighted
@code {
MarkupString highlighted;
[Parameter]
public string Value { get; set; }
protected override void OnParametersSet()
{
var value = Value ?? "";
var htmlBuilder = new StringBuilder();
for (var i = 0; i < value.Length; i++)
{
htmlBuilder
.Append("<span class=style-").Append(i % 3).Append('>')
.Append(HtmlEncoder.Default.Encode(value[i].ToString()))
.Append("</span>");
}
highlighted = new MarkupString(htmlBuilder.ToString());
}
}
The component generates the right html. However, the style is not applied:
CSS isolation occurs at build time. During this process, Blazor rewrites CSS selectors to match markup rendered by the component. In this case, the generated CSS file looks like:
.style-0[b-c2x6l882ml] { background-color: darkgrey; }
.style-1[b-c2x6l882ml] { background-color: orange; }
.style-2[b-c2x6l882ml] { background-color: chartreuse; }
To match the CSS selector, the span
s must have the attribute b-c2x6l882ml
. But this value is generated by Blazor at build time and is not accessible from the code at runtime. Instead of hardcoding it in the component, you can set a fixed value by editing the csproj file:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Update="Pages/Highlighter.razor.css" CssScope="b-highlight" />
</ItemGroup>
</Project>
If you rebuild the project, the generated css file should contain the specified scope:
.style-0[b-highlight] { background-color: darkgrey; }
.style-1[b-highlight] { background-color: orange; }
.style-2[b-highlight] { background-color: chartreuse; }
You can now edit the component to add this attribute to the span
elements:
...
for (var i = 0; i < value.Length; i++)
{
htmlBuilder
.Append("<span b-highlight class=style-").Append(i % 3).Append('>')
.Append(HtmlEncoder.Default.Encode(value[i].ToString()))
.Append("</span>");
}
...
Now the page renders as expected:
#Additional resources
- ASP.NET Core Blazor CSS isolation - Customize scope identifier format
- Rendering raw/unescaped HTML in Blazor
- CSS isolation in Blazor
Do you have a question or a suggestion about this post? Contact me!