Web interfaces contain several elements that can be open or closed: disclosure widgets, dialogs, select pickers, date inputs, and color pickers.
Historically, styling those states required different selectors. A disclosure could use details[open], while native picker state often had no equivalent general selector.
The CSS :open pseudo-class provides one semantic selector for elements that are currently in an open state. MDN marks it Baseline 2026 Newly available since May 2026 across the latest core browser versions.
Older browsers still exist, so production use should include fallbacks where the open styling is essential.
Start with details
The familiar approach is:
details[open] > summary {
background: #eef2ff;
}
With the pseudo-class, the selector expresses the state directly:
details:open > summary {
background: #eef2ff;
}
Both can coexist during migration:
details[open] > summary,
details:open > summary {
background: #eef2ff;
}
The attribute selector is a dependable fallback for details and dialog because those elements reflect their state through the open attribute.
Style an open select
One of the more interesting uses is a native select while its picker is displayed.
select {
border: 1px solid #94a3b8;
border-radius: 0.625rem;
padding: 0.65rem 0.8rem;
}
select:open {
border-color: #4f46e5;
box-shadow: 0 0 0 3px rgb(79 70 229 / 20%);
}
That state was difficult to target consistently with older CSS alone.
Style the parent with :has()
:open becomes more useful when combined with :has().
.field:has(select:open) {
background: #f8fafc;
}
The field wrapper can now react when its child select is open without JavaScript adding and removing a class.
Keep the visual change helpful and subtle. Opening a picker should not cause nearby content to jump.
Inputs with picker interfaces
The selector can also match inputs while a browser-provided picker is open, including controls such as date or color inputs where supported.
:is(input[type="date"], input[type="color"]):open {
outline: 3px solid rgb(14 165 233 / 30%);
outline-offset: 2px;
}
The exact picker presentation varies by platform, so test real operating systems rather than relying only on desktop screenshots.
:open is not :popover-open
Popover elements have their own showing state and selector.
[popover]:popover-open {
opacity: 1;
}
Use :open for elements with semantic open and closed states. Use :popover-open for a popover that is currently showing.
These states can coexist in the platform, so choosing the correct selector makes the CSS easier to understand.
Open does not necessarily mean visible
Semantic state and visual rendering are different.
A details element can have its open state even if an ancestor hides it. :open reports the state; it does not guarantee that a user can currently see or interact with the element.
Avoid using it as a substitute for visibility or layout checks.
Feature detection
Use selector detection when the enhancement has no simple fallback.
@supports selector(:open) {
select:open {
border-color: #4f46e5;
}
}
For details and dialog, the [open] attribute remains a practical fallback. For native picker states, make sure the closed appearance is already complete and accessible.
Animation considerations
An open-state selector can trigger a transition, but not every element's hidden-to-visible behaviour is automatically animatable.
details > .content {
opacity: 0;
transition: opacity 180ms ease;
}
details:open > .content {
opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
details > .content {
transition: none;
}
}
Test closing as well as opening. Some elements stop rendering content immediately when they close, which can prevent the reverse transition from appearing as expected.
Accessibility rules still apply
CSS state selectors do not replace semantics.
- Use
<summary>as the interactive label for<details>. - Give dialogs an accessible name.
- Keep focus visible.
- Do not communicate open state through color alone.
- Ensure controls remain operable by keyboard.
- Respect reduced-motion and forced-colors preferences.
The browser supplies a state; your design still has to communicate it clearly.
A practical migration
- Keep
[open]fallbacks for existing details and dialogs. - Add
:openfor select and native picker enhancements. - Use
@supports selector(:open)for isolated new styling. - Test keyboard interaction, zoom, and multiple operating systems.
- Use
:popover-openinstead when the component is a popover.
Conclusion
:open is a small CSS feature with a useful effect: it gives several native controls a shared vocabulary for their active state.
It can remove JavaScript classes from simple visual changes, improve styling for native pickers, and make selectors read more like the interface behaviour they represent.
Use it as an enhancement, keep sensible fallbacks, and remember that state selection is only one part of an accessible component.
Sources:
This article was originally published by DEV Community and written by Vishal Singh.
Read original article on DEV Community