Skip to content

Feature request: Support for passing scoped CSS classes to components #12305

@julianthurner

Description

@julianthurner

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

When designing components, it's common practice to provide a base style that can be overriden selectively. Let's say I have a component called SomeTextField with

SomeTextField.razor

<div class="defaultStyle">
    <p>Some Text</p>
</div>

SomeTextField.razor.css

.defaultStyle {
    color: blue;
    height: 200px;
    width: 200px;
}

Now, let's assume that in 90% of the time, I need the text to be blue, but in the other 10%, it should be red. So if I want to re-use that Component elsewhere in my code, but change only the color, I need to wrap it in a <div> every time I want to override the style:

SomeGreaterComponent.razor

<div class="specializedStyle">
    <SomeTextField />
</div>

SomeGreaterComponent.razor.css

.specializedStyle ::deep .defaultStyle {
    color: red;
}

This creates unnecessary nesting and verbosity. Also, it clutters up the DOM tree by introducing an extra surrounding <div>.

One could argue that it would be possible to create an extra parameter to toggle only the color, but as components grow larger, it becomes unmaintainable to provide single parameters for every css variable that sometimes needs to be swapped out.

Overriding with inline styles instead is considered bad practice due to various reasons, one of them being that it introduces specificity issues. Also, this makes it impossible to use Sass/Scss.

A clean component library which tries to give the user as much flexibility as possible while simultaneously providing beautiful looking default styles that can be overridden selectively will have to resort to the approach I demonstrated above.

Describe the solution you'd like

It would be really nice if Blazor components accepted a class attribute by default which can be consumed from within and which provides the scoped CSS class name:

SomeTextField.razor

<div class="defaultStyle @class">
    <p>Some Text</p>
</div>

@code { //empty since @class is defined by default }

Usage in SomeGreaterComponent.razor changes to:

<SomeTextField class="specializedStyle" />

SomeGreaterComponent.razor.css changes to:

.specializedStyle {
    color: red;
}

And is compiled in the DOM to:

<div class="defaultStyle[b-w7f0potky0] specializedStyle[b-5ye2g91b1z]">
    <p>Some Text</p>
</div>

This would make overriding styles selectively a lot less verbose due to not needing to wrap the component in a div every time and simultaneously de-clutter the DOM.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions