Browser support
Timeless targets Baseline 2025 browsers. The floor is set by the newest feature it requires, which
is :state(): Chrome and Edge 125, Safari 17.5, and Firefox 126. There are no polyfills, so
support tracks the platform features below.
Versions are taken from MDN browser-compat-data and record the first release of each feature, not a support promise. Check Baseline for current data.
Required features
Section titled “Required features”All Baseline, and all older than the floor above except the last two rows, which set it. A browser missing any of these cannot render Timeless correctly.
| Feature | Chrome / Edge | Safari | Firefox | Used by |
|---|---|---|---|---|
| Custom elements | 54 | 10.1 | 63 | Every enhanced component |
<dialog> |
37 | 15.4 | 98 | Dialog, Sheet |
| Cascade layers | 99 | 15.4 | 97 | Every stylesheet |
:has() |
105 | 15.4 | 121 | Field, Choice, and Range layout |
color-mix() |
111 | 16.2 | 113 | Derived accent and danger fills |
| Popover API | 114 | 17 | 125 | Popover, Hover Card, Menu, Select, Combobox |
light-dark() |
123 | 17.5 | 120 | Tokens and themed surfaces |
:state() custom states |
125 | 17.4 | 126 | Toast and Color Picker state |
Progressive features
Section titled “Progressive features”All three are Baseline as well, but they landed much later than the floor, so a browser that is current-but-not-latest may still be missing them. Each degrades to something usable.
| Feature | Chrome / Edge | Safari | Firefox | Without it |
|---|---|---|---|---|
@starting-style and allow-discrete |
117 | 17.5 | 129 | Overlays appear and disappear without the enter and exit transition. |
| CSS anchor positioning | 125 | 26 | 147 | Overlay surfaces stay in normal flow next to their trigger instead of being anchored to it. They still open, close, dismiss, and trap focus correctly. |
| Invoker Commands | 135 | 26.2 | 144 | A dialog or modal sheet trigger needs JavaScript to open its panel, because the component falls back to its click listener. Popovers are unaffected: they use popovertarget. |
Anchor positioning is the widest gap in practice: Firefox only shipped it in 147, well above the Firefox 126 floor. It is a layout refinement rather than a functional requirement, so a popover in an older Firefox is fully usable, just not tethered to its trigger.
Invoker Commands are the one place where the markup you author decides which path runs. Put
command="show-modal" and commandfor on a Dialog or modal Sheet trigger and the browser opens the
panel itself, before the bundle loads; add command="close" to a close button and the platform
closes it and copies the button’s value into returnValue. Timeless reads those attributes and
stands down — it never writes them, since an attribute added during enhancement would be back to
needing JavaScript. Where the API is missing, the component’s click listener does the same work, so
one set of markup is correct everywhere.
Two limits come from the platform rather than from Timeless. An invoker can only name an id that
exists in the markup, so an invoked <dialog> needs an explicit one rather than a generated one.
And there is no built-in command for dialog.show(), so a non-modal Sheet cannot be opened
declaratively; leave command off that trigger and the click listener opens it. Its close buttons
still work declaratively.
Wide-gamut color
Section titled “Wide-gamut color”oklch(), oklab(), lch(), lab(), hwb(), and color(display-p3 …) are Baseline everywhere
Timeless runs — Chrome 111, Safari 15, Firefox 113 — so this is not a browser-support question. What
varies is the display: an out-of-gamut color is rendered clamped on an sRGB screen. Color Picker
parses and edits the value faithfully regardless, flags when a color falls outside the current
gamut, and offers an explicit clamp control so you can decide rather than guess.
Unsupported capability
Section titled “Unsupported capability”When a component needs a platform capability the browser lacks, enhancement stops and the authored markup is left exactly as written. Nothing is hidden, no public diagnostic attribute is added, and no polyfill is loaded. A Popover in a browser without the Popover API keeps its native trigger and content; the surface simply does not become a top-layer popover.
This is why every component page documents markup that already works before JavaScript runs.
What is tested
Section titled “What is tested”Automated coverage runs on every change:
- Chromium for the website and the component catalog.
- Firefox and WebKit for platform contracts: form association, native validation, dialog and popover behavior, and no-JavaScript rendering.
- axe WCAG 2.2 A and AA rules, plus reflow and text-spacing checks, on every documented route.
These are regression evidence, not a conformance claim. Keyboard, zoom, forced-colors, and screen-reader review with real assistive technology still belong to your release process.