Ever wondered why we're still passing string props through three layers of React components just to change the border colour of a card? We've become so accustomed to "prop-drilling" for visual variants that we've forgotten how much friction it adds to our design systems.

Right, let's talk about CSS Style Queries. This isn't just another incremental update; it's a fundamental shift in how we build component APIs. Since becoming broadly cross-engine usable in 2026, they've effectively killed the need for many of those awkward wrapper classes and JavaScript state-plumbing hacks we used to rely on.

The End of Prop-Drilling for Styles

In the past, if a .Card component needed to look different inside a .Sidebar than it did in the .MainContent, you had two choices. You could use a descendant selector (which is fragile and increases specificity) or you could pass a prop down through JavaScript to append a class like .card--compact.

Style queries change the game. According to the CSS Conditional Rules Module Level 5 spec, a container style query allows querying the computed values of a query container. This means a parent can simply set a CSS variable, and any descendant can look up the tree and say, "Oh, the parent is in compact mode? I'll adjust my padding accordingly."

.shell {
  container-name: app-shell;
  --density: compact;
}

@container app-shell style(--density: compact) {
  .button {
    padding-block: .375rem;
    padding-inline: .625rem;
  }
}

I've found this approach much cleaner for design systems. The API becomes CSS-first. The parent sets a token, the child reads it, and there's no need for the DOM to even know that a variant change is happening.

How Style Queries Actually Work

One of the coolest things about style queries is that, by default, all elements are query containers. You don't necessarily have to define container-type: inline-size like you do with size queries. As the W3C states: "By default, all elements are query containers for the purpose of container style queries."

  • Custom Properties: Currently, the most robust way to use style queries is via CSS custom properties (variables).
  • Computed Values: The query checks the computed value, not just the declared one.
  • Nearest Ancestor: By default, it looks at the nearest ancestor. If you need to skip levels, use container-name.

I've seen some confusion here: you cannot query an element's own styles. If you set --theme: dark on a

, that same
cannot have a style query targeting itself. It evaluates the ancestor.

Practical Implementation: The Card Variant

Let's look at a common scenario. You have a list of cards, and you want to toggle their appearance based on a high-level layout choice. Instead of mapping through an array in React to change classes, just set the token on the wrapper.

.card-list {
  --variant: primary;
}

.card {
  padding: 1rem;
  border: 1px solid grey;
}

@container style(--variant: primary) {
  .card {
    border-color: rebeccapurple;
    background: color-mix(in oklab, rebeccapurple 10%, white);
  }
}

It's genuinely exciting to see how this simplifies our components. We're moving away from "logic in JS, styles in CSS" toward a model where the context is defined in the data/structure, but the reaction is handled entirely by the style engine.

Browser Support and Caveats

We're in a great spot now in 2026. Chrome and Edge have had this since version 111, Safari joined the party with version 18, and Firefox 151 rounded out the support. It's safe for production, but there's a catch you should know about.

MDN notes that "the only style feature currently supported is custom properties, with or without a value." While the spec technically allows querying things like font-weight: 800, most engines are focused on custom properties for now. Honestly? That's fine. For design systems, tokens (variables) are exactly what we want to query anyway.

• • •

I cover this and the other twenty-seven CSS shifts of 2026 in Modern CSS 2026 on Amazon, my catch-up book for people who learned CSS five years ago.

Wrapping Up

  • Style queries allow components to react to ancestor tokens without prop-drilling or extra classes.
  • They rely on @container style(--variable: value) and work best with custom properties.
  • Always remember: you query the ancestor, not the element itself.

I'd encourage you to experiment with this in your next component refactor. Try replacing a complex cva() or classnames setup with a simple CSS variable on a container. It feels like magic.

If you want to go deeper and learn how to build real, production-ready CSS design systems step by step, check out my full course here: CSS Design Systems Course

Feel free to reach out and share your progress with me on Twitter or LinkedIn. I'd love to see what you're building!

Share: