The upgraded version of attr() is exactly the kind of CSS feature that makes you want to immediately open CodePen and start trying dumb little experiments.
For years, attr() has mostly lived in the content: bucket:
.tag::before {
content: attr(data-label);
}
Useful, but narrow.
The interesting part now is that attributes can be read as typed values. So instead of only pulling strings into generated content, CSS can parse them as lengths, colors, numbers, integers, and more.
That is enough to make attr() feel newly relevant, even if the best use cases are still pretty small-scale.
What Changed
Now we can do things like this:
.card {
grid-column: span attr(data-span type(<integer>), 1);
font-size: attr(data-size type(<length>), 1rem);
border-color: attr(data-accent type(<color>), currentColor);
}
That is a much bigger deal than it sounds. It means a bit of data already sitting in the markup can become a real styling input without getting translated through inline styles or extra template logic first.
A Few Experiments That Feel Immediately Fun
1. Small layout hints
If you have a simple card grid and want a couple of items to span wider, this is the first pattern that feels surprisingly natural:
<article class="card" data-span="2">
<h2>Release Notes</h2>
</article>
.card {
grid-column: span 1;
}
@supports (x: attr(x type(*))) {
.card[data-span] {
grid-column: span attr(data-span type(<integer>), 1);
}
}
It is small, readable, and kind of satisfying. The HTML carries the hint, and CSS decides what to do with it.
See the Pen Advanced attr() Grid Span by pioneerlike on CodePen.
2. Theme accents coming from content or CMS data
This one is probably the most immediately useful to me. If content already has a color-ish value attached to it, CSS can finally consume it directly.
<li class="status-pill" data-accent="oklch(62% 0.18 145)">
Healthy
</li>
.status-pill {
color: attr(data-accent type(<color>), currentColor);
box-shadow: inset 0 0 0 1px attr(data-accent type(<color>), currentColor);
}
The nice part is that it still feels like CSS. You are not dumping a full style attribute into the markup, you are just handing CSS a typed input.
See the Pen Advanced attr() Accent Colors by pioneerlike on CodePen.
3. Typography tweaks for tightly-scoped content modules
This also gets interesting for content modules or CMS-driven blocks where you want a little flexibility without inventing a bunch of special classes.
<div class="promo-title" data-size="1.35rem">
Spring launch week
</div>
.promo-title {
font-size: attr(data-size type(<length>), 1.125rem);
}
I would not build an entire type system this way, but that is not really the point. The point is that some small configuration values can now stay where they already are instead of being copied somewhere else.
The Real Appeal
What I like most here is that it makes HTML feel a little more expressive without requiring much ceremony.
There has always been a slightly awkward gap between “this element has a value attached to it” and “CSS can do something meaningful with that value.” Usually the answer was one of:
- add another class
- use an inline style
- write a bit of JavaScript
- push more work into templates
Advanced attr() does not replace any of those. It just gives us another option, and for certain small UI patterns it is a pretty elegant one.
The Current Vibe
This is still very much a feature to experiment with, poke at, and keep in the mental toolbox for later. The support story is what it is, so for now the fun is mostly in discovery.
But I do think this is one of those features that will quietly lead to some nice patterns once it settles in. Not because it changes CSS architecture in some grand way, but because it removes a tiny bit of friction in places where the platform used to feel oddly rigid.
That is usually how the good CSS features land anyway. You play with them first, and only later realize they made a few annoying problems less annoying.