Using raw html with isolated CSS in Blazor

  • Gérald Barré

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 spans 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

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee