nested selectors without a preprocessor
With Tailwind v4, native CSS nesting officially enters the workflow through the new Rust-based engine. Developers coming from years of Sass nesting need to adjust a few habits, but gain a technique that runs directly in the browser with no preprocessor at all.
Table of Contents
- 1. Why CSS nesting matters for utility-first developers
- 2. Native CSS nesting basics: the & selector
- 3. How Tailwind v4's Oxide engine processes native nesting
- 4. The difference from Sass nesting habits
- 5. Using nesting well with @apply compositions
- 6. When nesting actually makes sense in a utility-first context
- 7. Nested media queries and container queries
- 8. Browser compatibility of native CSS nesting
- 9. Best practices for nesting in Tailwind projects
- 10. Summary
- 11. FAQ
1. Why CSS nesting matters for utility-first developers
Anyone working consistently utility-first writes very little custom CSS, because classes are combined directly in the markup. Still, there are situations where custom CSS is unavoidable, for example complex pseudo-element chains, integrating third-party widgets whose markup you don't control, or recurring compositions of many utility classes bundled into a named class through @apply. In exactly these edge cases, CSS nesting used to be strictly a Sass or PostCSS affair that required an extra build step.
With native CSS nesting joining the CSS specification and gaining broad browser support, that dependency disappears. Tailwind v4 leans into this by having its new build engine understand native nesting directly, flattening it for older target environments only where necessary. For developers, that means nested selectors can be written in custom CSS files without a separate Sass compiler hanging off the build pipeline, which slims down the toolchain and cuts build times.
2. Native CSS nesting basics: the & selector
Native CSS nesting lets you write a rule directly inside another rule, with the ampersand acting as a placeholder for the enclosing selector. A rule like .card { & p { margin: 0; } } is exactly equivalent to the flat form .card p { margin: 0; }, except the relationship between the two selectors is visible right in the source instead of being expressed across two separate, potentially far-apart rules. The ampersand can appear anywhere in the nested selector, including at the end for pseudo-classes such as &:hover or &.is-active.
It's worth noting that native nesting doesn't strictly introduce a new language; it's simply a more compact notation for selector combinations that flat CSS has always supported. The browser resolves the nesting internally into ordinary flat selectors while parsing, so specificity and cascade behavior fundamentally don't change, which means developers with basic CSS knowledge can pick it up immediately without learning a new syntax.
3. How Tailwind v4's Oxide engine processes native nesting
Tailwind v4 was rebuilt from the ground up on a new engine written in Rust, internally known as the Oxide engine, which uses Lightning CSS among other things for transforms such as vendor prefixing, minification, and CSS nesting. For projects that want to write native CSS features directly instead of exclusively combining utility classes in markup, this means nested CSS inside @layer blocks or in custom stylesheet files works without any additional Sass dependency.
The example below defines a card component with nested rules for an inner title and a hover state, combined with a utility base pulled in through @apply. The Oxide engine evaluates this structure at build time and produces optimized, flat CSS for delivery, while the source stays readable and logically grouped for developers.
.card {
@apply rounded-lg border border-gray-200 p-4 shadow-sm transition-shadow;
& .card-title {
@apply text-lg font-semibold text-gray-900;
}
&:hover {
@apply shadow-md;
}
&.is-featured {
@apply border-blue-400 bg-blue-50;
}
}
4. The difference from Sass nesting habits
Developers coming from Sass are used to implicit nesting, where a child selector combines with its parent automatically even without an ampersand, for example .card { p { margin: 0; } } with no leading character at all. Native CSS nesting, by contrast, often requires an explicit & as a separator, particularly when a pseudo-selector, a class, or an attribute selector follows directly, because the CSS specification is stricter here than the Sass preprocessor ever was.
Another difference concerns media queries and other at-rules: Sass has always allowed nesting @media blocks inside selector rules, and native CSS nesting now supports that too, though with a somewhat different internal resolution order that can, in rare edge cases, lead to slightly different specificity. Anyone porting existing Sass files one-to-one into native nesting should check each nested rule individually rather than assume identical behavior.
5. Using nesting well with @apply compositions
The most natural place for native nesting in a Tailwind project is recurring component classes assembled from multiple utility classes through @apply, for example buttons, badges, or card components that need to look identical wherever they're used. Instead of repeating a separate flat rule with a full selector for every state, every inner building block, and every pseudo-class, these variants nest directly inside the main rule, which makes the relationship visible right in the source.
This bundling is especially helpful when a component has several related sub-states, for instance hover, focus, and disabled states that all conceptually belong to the same class. Rather than maintaining three separate rules scattered across different parts of the file, nesting keeps a component's complete definition in one place, which makes maintenance and refactoring noticeably easier, particularly in larger projects with many reused component classes.
6. When nesting actually makes sense in a utility-first context
In a strictly utility-first project, the need for custom nested CSS stays fundamentally small, because most styling decisions happen directly in the markup through utility classes and never need a dedicated CSS rule. Nesting pays off where a component is reused many times across the project and the utility classes in the markup itself would already be unwieldy, or where third-party markup needs styling and offers no classes of its own for targeted utility application.
A typical warning sign of overusing nesting is when a nested CSS file starts to recreate the same structure as a full component library, with deeply nested selectors spanning many levels. At that point it's worth asking whether a real reusable component in Alpine.js or a PHTML template partial wouldn't be the cleaner solution, rather than using CSS selectors as a substitute for missing component structure.
7. Nested media queries and container queries
Native CSS nesting works not only with regular selectors but also with at-rules such as @media and @container, which can be nested directly inside a component rule. For Tailwind projects that define their own container query breakpoints in addition to the built-in responsive prefixes, that means a component's responsive logic can sit right next to its base definition instead of ending up in a separate media query block at the end of the file.
That spatial closeness between the base rule and its responsive adjustment noticeably improves readability, since a developer reading a component definition immediately sees which responsive variants exist, instead of scanning the file for scattered media query blocks. This closeness pays off especially with container queries, which modern Tailwind projects increasingly use instead of classic viewport media queries, since the container context and the component are tightly coupled anyway.
8. Browser compatibility of native CSS nesting
Native CSS nesting is supported by all current versions of the major browser engines, meaning Chrome and Edge on Blink, Firefox on Gecko, and Safari on WebKit, with support maturing steadily since each engine's rollout starting in 2023. For projects that still need to support older browser versions, the Tailwind v4 build engine automatically resolves nesting into flat CSS, producing a stylesheet compatible with older target environments without developers having to give up the more compact notation manually.
This automatic transformation means the decision to use native nesting in the source is independent of the actual target browser support, since the build process handles the translation. It's still worth setting a realistic browserslist configuration for the project, so the engine knows how aggressively it needs to transform and whether a more modern, compact output is possible or a more conservative, broadly compatible variant is required instead.
9. Best practices for nesting in Tailwind projects
A solid rule of thumb is to keep nesting to at most two or three levels deep, because deeper nested CSS reintroduces the same readability problems that utility-first was meant to avoid in the first place, namely hard-to-follow specificity chains. Instead of building a deep hierarchy with many levels, a flatter structure with clearly named component classes, each nested on its own without nesting into each other, is usually the better fit.
It's also worth deliberately reserving native nesting for cases where a component genuinely needs several related rules, rather than as a general replacement strategy for utility classes in markup, since doing so would erase Tailwind's core advantage of making styling decisions directly visible in the HTML. Nesting is a tool for the minority of cases where real CSS is required, not a substitute for the utility-first approach as a whole.
| Aspect | Sass nesting | Native CSS nesting | Tailwind v4 |
|---|---|---|---|
| & selector | Optional, implicit nesting possible | Often required explicitly, especially before pseudo-classes | Handled correctly through the Oxide engine |
| Nested media queries | Yes, supported for a long time | Yes, since the 2023 browser rollouts | Possible right next to the component rule |
| Compilation | Requires a build step with a Sass compiler | No build step, runs natively in the browser | Flattened automatically for older target browsers when needed |
| Dependencies | node-sass or dart-sass as a dev dependency | None, part of the CSS specification | No additional dependency beyond Tailwind itself |
Mironsoft
Tailwind CSS architecture, design systems, and performance
Tailwind frontends that stay maintainable despite thousands of utility classes?
We review existing Tailwind projects for bloated class lists, inconsistent design tokens, and unused CSS remnants, then build a design system that scales cleanly instead of getting messier with every component.
Design System Review
Checking tokens, spacing scale, and component consistency for maintainability.
Performance Optimization
Systematically reducing CSS bundle size, purge configuration, and load times.
Component Architecture
Building reusable, well-structured components instead of sprawling class lists.
10. Summary
Native CSS nesting in Tailwind v4 at a glance
& selector
Placeholder for the enclosing selector, often required explicitly before pseudo-classes.
Oxide engine
Tailwind v4's Rust engine processes native nesting and flattens it when needed.
Sass difference
No implicit nesting, an explicit & is needed before classes and pseudo-selectors.
Where to use it
Mainly worthwhile for @apply compositions and recurring component classes.