
One of the most useful, yet often overlooked, aspects of Blazor’s CSS isolation support is the ability to style child components. At first glance, it may appear that isolated CSS can only be applied to the component to which it is attached; however, with a little help from the ::deep pseudo-selector (the “deep combinator”), it’s possible to propagate styling to child components too.
In this post, I’ll cover how child component styling works with Blazor CSS isolation and address a common pitfall that can prevent styles from being applied correctly.
Blazor CSS Isolation
Blazor provides CSS isolation support, meaning that a set of styles can be scoped to a specific component. This is a hugely useful feature, as it prevents styling rules from unintentionally affecting other components and keeps the rules as close as possible to the component definition for easier maintenance.
Component-specific styles are applied in Blazor by creating a .razor.css file alongside your .razor component. The .razor.css file is known as a scoped CSS file.
Child components
By default, isolated component styles only affect the immediate component that the scoped CSS file is associated with. This is accomplished via a build-time rewrite. Blazor generates a scope identifier attribute (e.g. something like b-7fdedf8f43) that is added to the HTML of the component and then rewrites the CSS to target the generated attribute.
The isolated CSS rules do not automatically “bleed” into child components because Blazor doesn’t know at compile-time exactly how deep your component tree goes. This is generally a good thing, as it helps to avoid accidentally applying styles to child components that you didn’t intend to.
To deliberately apply styles to child components, we can leverage the ::deep combinator. This is a pseudo-element specific to the Blazor framework that is transformed at compile-time such that it selects elements that are descendants of an element’s scope identifier.
As an example, let’s say we write some CSS such as the following within a parent component CSS file.
::deep .class-defined-in-child-component {     color: red; }
With this parent component CSS file, Blazor understands that a .class-defined-in-child-component CSS class might exist in a child component and will arrange things so that the CSS can match those descendant elements.
Why you might need a wrapper element
Here’s a common gotcha that has the potential to trip up many developers. For the ::deep combinator to apply styles to child components properly, it’s often necessary to wrap child components with a plain HTML element, typically a div.
Why is this?
Well, it’s due to the way Blazor emits the generated attribute that enables the CSS isolation. The ::deep combinator is translated into a selector that requires the scope-attribute on a host element, and it only matches descendants of that host. In simpler terms, the ::deep combinator only works with descendant elements.
If the markup of your .razor file is just a component at the top level, such as the following.
<ChildComponent />
Blazor will not be able to apply styles to the child component in this case, as a descendant relationship cannot be established.
Practical example
Let’s look at a simple, practical example to make this very clear.
Imagine we have a component named ParentComponent.razor with the following content.
<h3>Parent Component</h3> <span class="label">This is the parent component content.</span> <ChildComponent />
As you can see, the component has been designed to render some header text, some label text, and a child component, which we’ll see in a second.
Alongside the Razor file, we have a scoped CSS file, named ParentComponent.razor.css with the following content.
.label {     font-weight: bold;     color: blue; }
The above CSS will result in the targeted element (in this case, the span element) rendering bold blue text.
The contents of the ChildComponent.razor file are as follows.
<h3>Child Component</h3> <span class="label">This is the child component content.</span>
The child component is similar to the parent, containing markup to render some header text and some label text, with a span element and the same class attribute value.
If we render ParentComponent within the Index page of the standard Blazor sample application, the page will render as shown in the screenshot below.

As you can see, although the child component also has an element with a class of “label”, only the parent component is affected by the CSS rule that targets elements with that class.
We can add some style rules to ParentComponent.razor.css that can affect child components by using the ::deep combinator as shown in the following updated file contents.
.label {     font-weight: bold;     color: blue; } ::deep .label {     font-weight: bold;     color: red; }
However, if we run the application again, we’ll see that the page looks the same.
To resolve this, we can wrap the child component with a div element, as shown in the updated ParentComponent.razor file contents below.
<h3>Parent Component</h3> <span class="label">This is the parent component content.</span> <div>     <ChildComponent /> </div>
Now, when we run the application, we’ll see that the styles that were defined in ParentComponent.razor.css are now being applied as expected to ChildComponent elements, as shown in the screenshot below.

You can achieve the same result by giving the wrapper element an id or class as shown below.
<h3>Parent Component</h3> <span class="label">This is the parent component content.</span> <div class="child-wrapper">     <ChildComponent /> </div>
The CSS can then be updated to the following.
.label {     font-weight: bold;     color: blue; } .child-wrapper ::deep .label {     font-weight: bold;     color: red; }
This technique is useful for cases where you have lots of element/component nesting and need to apply the styles in a more targeted way that only affects a specific level within the hierarchy.
Wrapping up
CSS isolation in Blazor is a powerful feature, ensuring the encapsulation of styles and reducing the risk of unintended side effects to other components.
The ::deep combinator provides a controlled way to define styles that reach into child components. However, I don’t recommend using ::deep unless you really need to. Ideally, your components will follow a design standard and will be flexible enough to make ::deep styling largely unnecessary.
That being said, there are always going to be exceptions to the rule and ::deep can be a useful escape hatch, especially when you need to apply one-off styles to third-party components that you have less control over. It’s important to be aware that this can leave things more brittle, as the internal structure of the components could change and invalidate your custom styles.
In summary, remember that every feature has its purpose, and the ability to style child components from parent components within the confines of CSS isolation is a feature that should be wielded wisely. For cases where you find that the styles aren’t being applied using the ::deep combinator, remember that you may need a wrapper element!


Comments