Container style queries + advanced attr(): rethinking component architecture in CSS 🎨🧩
Advanced attr() and Container Style Queries pass typed HTML attributes into CSS and make components more autonomous.

A small revolution is quietly happening in CSS: the combination of Container Style Queries and the updated attr() function from the CSS Values and Units Module Level 5 specification is changing familiar approaches to passing styles from HTML.
In a new breakdown, Brecht De Ruyte shows how to stop churning out utility-class generators (like .grid-cols-3 or .card--compact) and pass parameters directly from HTML attributes into CSS without a single line of JS.
What can advanced attr() do?
Previously, attr() only worked inside pseudo-elements (content: attr(...)). Now, with typed values, we can pass any data directly into CSS properties:
- Converting to units:
gap: attr(data-gap cqi, 2cqi)takes the value ofdata-gap="3"and turns it into3cqion the fly. - Numbers and lengths:
attr(data-repeat type(<number>), 3)orattr(data-min type(<length>), 280px)lets you pass dynamic numbers directly intorepeat(). - Custom identifiers:
attr(data-density type(<custom-ident>), comfortable)returns a proper CSS identifier,compact, rather than the string"compact".
How does it work with Container Style Queries?
We can pass an attribute of type custom-ident into a custom CSS variable on the parent, and child elements will automatically adapt to it through @container style()!
<div class="card-grid" data-density="compact">
<article class="card">...</article>
</div>
.card-grid {
/* Записываем значение атрибута прямо в CSS-переменную */
--density: attr(data-density type(<custom-ident>), comfortable);
}
/* Дочерний элемент сам реагирует на переменную родительского контейнера */
@container style(--density: compact) {
.card {
padding: 0.5rem;
font-size: 0.875rem;
}
}
What makes this approach enjoyable?
- Clean HTML without utility hell: No bulky chains of classes, just clear data attributes.
- Contextual adaptability: Components become truly autonomous. They don’t care where they are. They query their parent’s computed styles.
- Minimal JS: To change the grid or UI density (for example, with a slider or view switcher), you only need to change one DOM attribute. The browser handles all the math and animation.
Read the full breakdown with interactive demos
What do you think of passing typed data through
attr()together with style queries? Or do good old Tailwind classes still feel more familiar? 👇