DEV Community

Cover image for Configurable CSS Components
Mads Stoumann
Mads Stoumann

Posted on

Configurable CSS Components

The CSS attr() function is getting updated to support any property.

This enables the creation of configurable CSS components, which allow content creators to specify properties directly, using custom tags and attributes.

This article showcases three examples: a gradient text, an underline, and a fade-out component. While the new attr() syntax is not yet supported in browsers, custom properties can be used as a fallback.


With the current implementation, the attr()-function can set the content-attribute of a pseudo-element (::before or ::after) from a HTML-attribute.

After the update, attr() works with all properties, not just content.

It will also support types and fallbacks, so you can define a property as, let's say, a color, and specify the fallback-color, if the property is empty:

color: attr(data-cl color, #DC143C);
Enter fullscreen mode Exit fullscreen mode

What does that mean?

While this may not seem like a groundbreaking change, it is (at least for for me!)

Imagine a headline like this:

Headline

It consists of a gradient text, a custom underline and a fadeout.

To allow a content-creator to specify the gradient-text colors, the height or color of the underline — or the angle of the fade-out, would require loads of modifier-classes and extra CSS to maintain.

But with the ability to set a property directly (with failsafe types) using attr(), we can create configurable CSS components.

Let's create a bunch — starting with <gradient-text>:


Gradient Text

First, we create a custom tag, <gradient-text> with two attributes, from and to:

<gradient-text from="#06d" to="#0fd">
Enter fullscreen mode Exit fullscreen mode

For the CSS, it's simply:

gradient-text {
  background: linear-gradient(
    attr(angle angle, 135deg), 
    attr(from color, #8E6BC8), 
    attr(to color, #00E9EE)
  );
  background-clip: text;
  -webkit-background-clip: text;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  color: transparent;
}
Enter fullscreen mode Exit fullscreen mode

You can use the custom tag today, but it won't work with the new attr(), as it's not supported in any browsers yet.

We need a fallback, using @supports:

gradient-text {
@supports( color: attr(data-c color, red)) {
  --angle: attr(angle angle, 135deg);
  --from: attr(from color, #8E6BC8);
  --to: attr(to color, #00E9EE);
}
  background: linear-gradient(
    var(--angle, 135deg),
    var(--from, #8E6BC8),
    var(--to, #00E9EE)
  );
  /* ... */
}
Enter fullscreen mode Exit fullscreen mode

First, we check whether the new attr()-syntax is supported. If it is, we're setting a bunch of custom properties to the attribute-values. Then, outside the fallback, we'll use these properties for the gradient.

Examples:

<gradient-text from="#06d" to="#0fd">
Enter fullscreen mode Exit fullscreen mode

Custom tag gradient-text

— and with the optional angle-attribute:

<gradient-text from="#06d" to="#0fd" angle="190deg">
Enter fullscreen mode Exit fullscreen mode

gradient-text with angle


Underline

The <under-line>-component is almost identical to the <gradient-text>-component. It has a from and a to-attribute, but if you don't specify to, it's set to from. Instead of angle, it has a height-attribute.

Examples:

<under-line from="#27D2C6" to="#9FFFF9">
Enter fullscreen mode Exit fullscreen mode

— and —

<under-line from="#fcd4ff" height="10%">
Enter fullscreen mode Exit fullscreen mode

Which gets us:

Underline

The CSS follows the same structure as before, with a @supports-fallback first:

under-line {
@supports( color: attr(data-c color, red)) {
  --from: attr(from color, #FCD4FF);
  --to: attr(to color, #FCD4FF);
  --height: attr(height length, 25%);
}
  background-image: linear-gradient(
    90deg,
    var(--from, #FCD4FF), 
    var(--to, var(--from, #FCD4FF))
  );
  background-position: left bottom;
  background-repeat: no-repeat;
  background-size: 100% var(--height, 25%);
}
Enter fullscreen mode Exit fullscreen mode

Fadeout

Like the previous components, the <fade-out>-component have a from and a to-attribute.

fade-out {
@supports( color: attr(data-c color, red)) {
  --angle: attr(angle angle, 90deg);
  --from: attr(from %, 50%);
  --to: attr(to %, 100%);
}
  --mask: linear-gradient(
    var(--angle, 90deg),
    #000 var(--from, 50%),
    #0000 var(--to, 100%)) 
    0vw 0vw no-repeat;
  -webkit-mask: var(--mask);
  mask: var(--mask);
  white-space: nowrap;
}
Enter fullscreen mode Exit fullscreen mode

Examples:

<fade-out from="50%" to="100%">
Enter fullscreen mode Exit fullscreen mode

— and with optional angle-attribute:

<fade-out angle="180deg" from="0%" to="90%">
Enter fullscreen mode Exit fullscreen mode

Which gets us:

Fade-out component


Conclusion

In conclusion, the introduction of the updated attr()-function in CSS, opens up new possibilities for creating configurable CSS components.

As we've seen in the examples, content creators can easily specify properties such as colors, heights, and angles without the need for extra CSS or modifier classes.

Although the new attr() syntax is not yet supported in any browsers, we can use custom tags with fallbacks using the @supports rule to achieve similar effects.

If you want to use the custom tags from the examples today, you need to update the custom properties (--to, --from etc.) instead of using attributes.

You can do this with modifier-classes, or write a small JavaScript-snippet, that'll set the custom properties from the attributes, so:

<gradient-text from="#06d" to="#0fd">
Enter fullscreen mode Exit fullscreen mode

becomes:

<gradient-text style="--from:#06d;--to:#0fd">
Enter fullscreen mode Exit fullscreen mode

Cover Photo by Alexander Grey

Top comments (2)

Collapse
 
afif profile image
Temani Afif

Are you able to test this in any browsers (even with flag enabled)?

attr() are defined to work with any property since too long (An example I remember from 2019: stackoverflow.com/q/56613889/8620333) but 0 browser support 😞

Collapse
 
madsstoumann profile image
Mads Stoumann • Edited

No, not a single one, I’m afraid! Hence all the fallback-stuff.
But MDN has an example with background-color being set from an attribute, that I didn’t see earlier — that’s what triggered me, since I had to do these components for a website.