Configurable CSS Components
Tags: css, showdev, webdev
Published: 2023-05-07 07:54:19

The CSS `attr()` function is [getting updated](https://developer.mozilla.org/en-US/docs/Web/CSS/attr()) 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:

```css
color: attr(data-cl color, #DC143C);
```

---

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvqg6l14bo0zhronjsy9.png)

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`:

```html
<gradient-text from="#06d" to="#0fd">
```

For the CSS, it's simply:

```css
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;
}
```

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`:

```css
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)
  );
  /* ... */
}
```

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:_

```html
<gradient-text from="#06d" to="#0fd">
```

![Custom tag gradient-text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rewshub0rh66cmiwfxit.png)

— and with the optional `angle`-attribute:

```html
<gradient-text from="#06d" to="#0fd" angle="190deg">
```

![gradient-text with angle](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1503dafqmlbska7zwz8d.png)

---

## 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:_

```html
<under-line from="#27D2C6" to="#9FFFF9">
```

— and —

```html
<under-line from="#fcd4ff" height="10%">
```

Which gets us:

![Underline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3sk2ydy252idh6eszt99.png)

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

```css
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%);
}
```

---

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

```css
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;
}
```

_Examples:_

```html
<fade-out from="50%" to="100%">
```

— and with optional `angle`-attribute:

```html
<fade-out angle="180deg" from="0%" to="90%">
```

Which gets us:

![Fade-out component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zz74ouqfnfkcpncrtxz.png)

---

## 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:

```html
<gradient-text from="#06d" to="#0fd">
```

becomes:

```html
<gradient-text style="--from:#06d;--to:#0fd">
```

---

Cover Photo by [Alexander Grey](https://www.pexels.com/da-dk/foto/mursten-sloring-farverig-farver-1148496/)