sveltelean
Versionv0.2.0 GitHub

Policy

A native primitive uses a platform feature directly, so the browser target is the feature's support, not a version list chosen by the package. Each contract records the features it relies on and their Baseline status; the compatibility document turns that into one table and, from release stage 4 on, into a versioned promise. Until then the statements on this page describe what is tested, not what is guaranteed.

  • Native paths depend on Baseline features and stay native; no fallback logic is mixed in.
  • Compatibility code is opt-in or target-selected and never silently bundled into a native path (shipping invariant E of ADR 0005). No compatibility module exists today.
  • Feature detection comes before user-agent detection. The packages contain no browser-name branching and, today, no feature detection either: the native paths use the feature and the stylesheet relies on CSS fallback behavior.
  • No target option exists in the Vite plugin; the blueprint names one as a future direction, and it is not built.

Feature table

One row per capability: the native path, the compatibility path and the fallback. The Baseline column repeats what each contract documents as of 2026-09-27; the sections further down quote the contracts themselves.

Feature (native path)Used byBaseline status, documented in the contract as of 2026-09-27Compatibility pathWithout support
<dialog>, showModal(), the top layer, ::backdrop, page inertnessDialogWidely available (newly available in 2022)none exists; the package does not polyfillNo fallback is documented; the element is the base of the primitive
Invoker commands (command, commandfor)Dialog and Popover invokers, ButtonNewly available, not yet widely: Chrome 135, Safari 26, Firefox 144, shipped during 2025None exists; an opt-in module is named as an option in ADR 0005Two calls in application code (showModal(), close()); without them the dialog stays closed
Popover API (popover, popovertarget, popovertargetaction, :popover-open, ToggleEvent)Popover, Menu, Menubar, Combobox, Tooltip, Hover card, Toast, Context menu, Date picker, the mobile navigation of this siteNewly available since April 2024: Chrome 114, Safari 17, Firefox 125none exists; the package does not polyfillThe attribute is ignored and the content renders inline; a menu loses its top layer and light dismiss; a combobox uses a hidden-toggled popup instead
showPopover({ source })Combobox popup (the input as the implicit anchor and invoker), TooltipNot Baseline: Chrome 133, Safari 26none exists; the package does not polyfillPassed as an option that browsers without it ignore; popover="manual" needs no invoker relationship
CSS anchor positioning (position-area, position-try-fallbacks)Popover, Menu and Tooltip placement in the stylesheetNot Baseline: Chrome 125, Safari 26None exists; an optional positioning module is a named possibility, not a planThe platform default placement: centered in the top layer
CSS anchor positioning (anchor-name, anchor-scope, position-anchor, position-area, anchor-size())Combobox popup placement in the stylesheetNot Baseline: Chrome 125 (anchor-scope 131), Safari 26none exists; the package does not polyfillA hidden-toggled popup is positioned under the root with absolute positioning; a popover popup is centered in the top layer
KeyboardEvent.isComposingCombobox (keys during an IME composition are ignored)Widely available; keyCode 229 covers browsers that report the state latenone exists; the package does not polyfillNo fallback is documented
AbortSignal on addEventListener, Element.isConnectedCombobox session listener (Tier 2 scoped controller)Widely availablenone exists; the package does not polyfillNo fallback is documented
<details>, <summary>, the toggle eventDisclosureWidely availablenone exists; the package does not polyfillNo fallback is documented; the element is the base of the primitive
name on <details> for exclusive groupsDisclosure accordionsNewly available since September 2024: Chrome 120, Safari 17.2, Firefox 130none exists; the package does not polyfillSiblings stay open independently
::details-content, interpolate-sizeDisclosure open transition in the stylesheetUsed only where supported; nothing depends on themnone exists; the package does not polyfillNo transition
appearance: none on checkboxes, :checked, :indeterminateCheckbox, SwitchWidely availablenone exists; the package does not polyfillNo fallback is documented
:user-invalidValidation styles of Checkbox, Input, Date field, One-time code and File fieldBaseline 2023none exists; the package does not polyfillNative validation still works; the invalid styling does not apply
role="switch" on a checkbox (ARIA 1.2)SwitchMapped by current screen readersnone exists; the package does not polyfillAnnounced as a checkbox where the role is not mapped
<button>, :focus-visibleButtonWidely availablenone exists; the package does not polyfillNo fallback is documented
<fieldset>, <legend>, <input type="radio">Radio groupWidely availablenone exists; the package does not polyfillNo fallback is documented
:dir(rtl), read only to resolve dir="auto"Tabs, Listbox, Tree, Toggle group, Toolbar, Calendar, Splitter and every behavior with horizontal arrow keysGuarded in packages/primitives/src/internal/direction.tsnone exists; the package does not polyfilldir="auto" resolves to left-to-right; an explicit dir attribute always works
ES2022 JavaScript, composedPath()Every Tier 1 and Tier 2 behavior (the shared router)The output target of every package; no transpilation to an older targetRun the packages through your own bundler for an older targetWithout the runtime every primitive keeps its server-rendered state and native parts: tabs cannot switch, a menu opens as a plain popover, a combobox is a plain text field; each contract states its own case
popover="hint"Tooltip, Hover cardNot Baseline: Chrome 133none exists; the package does not polyfillThe value falls back to a manual popover, which the behavior hides itself
Customizable select (appearance: base-select, ::picker(select), ::checkmark, <selectedcontent>)SelectNot Baseline: Chrome 135, Safari 27; not in Firefoxnone exists; the package does not polyfillThe styled closed box with the platform picker
closedby on <dialog>Alert dialog, DrawerNot Baseline: Chrome 134, Firefox 141; not in Safari 27none exists; the package does not polyfillEscape still cancels an alert dialog; a click on the backdrop does not close a drawer
transition of overlay (with transition-behavior: allow-discrete)Exit transitions of Alert dialog and DrawerNot Baseline: Chrome 117; not in Safari 27none exists; the package does not polyfillThe exit transition runs after the dialog has left the top layer
field-sizing: contentInput (textarea)Newly available since June 2026: Chrome 123, Safari 26.2, Firefox 152none exists; the package does not polyfillThe textarea keeps the height of its rows and scrolls
:has()Segmented control, Rating, Steps, Field, Number field, Range slider, Context menu stylesBaseline 2023none exists; the package does not polyfillThe state drawn from a descendant is not drawn (the checked segment, the filled stars, a complete step); the native controls keep working
Vertical form controls (writing-mode on <input type="range">)Slider, verticalBaseline 2024: Chrome 124, Firefox 120, Safari 17.4none exists; the package does not polyfillThe slider is drawn horizontally
Form control pseudo-elements (range thumb and track, progress value, meter regions)Slider, Range slider, Progress, MeterNot standardized: -webkit- and -moz- pseudo-elementsnone exists; the package does not polyfillThe platform draws the control
<datalist> suggestionsAutocompleteNot Baseline as a feature; the list attribute is widely availableThe Combobox primitive renders and styles its own optionsA plain text field; the typed value is still submitted
The contextmenu eventContext menuWidely available; Safari on iOS does not dispatch it for a long pressnone exists; the package does not polyfillTouch-only iPhone and iPad users cannot open the menu; offer the actions elsewhere
Dropping files on <input type="file">; dragenter, dragleave, dropFile dropWidely available; accept does not filter dropped filesnone exists; the package does not polyfillWithout JavaScript the input is shown as it is and still accepts a drop
Pointer events, pointer capture, touch-actionSplitterWidely availablenone exists; the package does not polyfillNo fallback is documented
@media (scripting)Date picker, Number fieldBaseline 2023none exists; the package does not polyfillThe trigger and step buttons stay visible without JavaScript and do nothing
round()Range slider (which thumb is on top where both meet)Baseline 2024none exists; the package does not polyfillThe end thumb stays on top
color-mix()Alert, Spinner, PaginationBaseline 2023none exists; the package does not polyfillThe tinted border or track takes a neutral token
Alternative text in content (content: counter() / "")StepsBaseline 2024none exists; the package does not polyfillA screen reader may read the step number with the step
accent-colorSlider with data-variant="native"Not Baseline: Chrome 93, Firefox 92, Safari 26.2none exists; the package does not polyfillThe platform slider in its default color
position: stickyTable sticky headerWidely availablenone exists; the package does not polyfillA normal header

This browser

Feature detection in the browser you are using, for the features the native paths depend on. The detection runs after the page loads and requires JavaScript; the proof page shows the same table next to the runtime it reads.

FeatureUsed byThis browser
Detection runs in the browser after load.

Outside the target

A missing feature degrades the way the contract describes, never into a JavaScript replacement pulled in without being asked. The one case that matters most today is invoker commands, which are newer than the other features: where command and commandfor are missing, a dialog needs two calls in application code, and nothing from the package.

settings.svelte
<script lang="ts">
	// Where invoker commands are missing: two calls in application code, no package involved.
	let dialog: HTMLDialogElement;
</script>

<button type="button" onclick={() => dialog.showModal()}>Settings</button>

<dialog bind:this={dialog} id="settings" data-slean="dialog" aria-labelledby="settings-title">
	<h2 id="settings-title" data-slean-part="title">Settings</h2>
	<button type="button" onclick={() => dialog.close()}>Close</button>
</dialog>

Application code that must branch on support should test the feature, not the browser name.

TypeScript
// Feature detection before user-agent detection: what application code may branch on.
const commands = 'commandForElement' in HTMLButtonElement.prototype;
const popover = 'popover' in HTMLElement.prototype;
const anchors = CSS.supports('position-area: bottom');

Tier 1 behaviors need the runtime: without JavaScript, tabs keep the state the server rendered (the selected panel visible, the others hidden) and cannot switch; pages that must work without script can render every panel without hidden and accept a stacked layout. A menu opens and closes as a plain popover, link items work, and movement inside is Tab-based. A listbox keeps its authored selection and cannot change it. The combobox, Tier 2, is a plain text field whose popup never opens; a form still submits what was typed, and a <datalist> is the native alternative for suggestions without script.

Compatibility modules

None exists. ADR 0005 names an opt-in module for invoker commands and the blueprint names an optional positioning module; both are possibilities, not plans. When one is built it will be a separate entry point selected by the application or by a build target, and a consumer fixture will assert that the native path does not include it (shipping invariant E). Until then the fallbacks in the table are the whole story.

Testing

Browser tests run in Chromium only: the locally installed Google Chrome, whose version is recorded in the audit and the benchmark file, and Playwright's Chromium in CI. The native contracts are exercised with page JavaScript disabled in native.spec.ts. Firefox and WebKit projects are declared in the playground's Playwright configuration; pull-request CI installs Chromium only and skips them, the nightly workflow runs both and fails when a project is skipped, and no run is recorded in this repository yet. A recorded run is a stage 2 requirement in docs/release.md; when it exists it will assert the documented fallback, not the native path, in a browser that lacks a feature. No cross-browser claim is made until then.

Contract excerpts

The "Platform features and Baseline" section of every contract, read from the contract file when this site is built. The contracts are the source; this page cannot drift from them.

accordion

  • <details>, <summary> and the toggle event: Baseline widely available.
  • name for exclusive groups: Baseline newly available since September 2024 (Chrome 120, Safari 17.2, Firefox 130). Elsewhere every item opens on its own.
  • Find-in-page opens a closed item that contains the match: Chrome 97, Firefox 139, Safari 26.2. In an exclusive group this closes the item that was open.
  • ::details-content: Baseline newly available since September 2025 (Chrome 131, Safari 18.4, Firefox 143). interpolate-size: allow-keywords, which lets the styles animate the height to auto, is in Chrome 129 and not in Firefox or Safari; there the content appears without a transition.

Full contract on GitHub

alert

  • role="status" and role="alert" are ARIA 1.1 live region roles, exposed by every current browser. When and how a message is spoken differs between screen readers; the rules above are the ones that hold across them.
  • color-mix() mixes the tone borders; it is Baseline 2023. Without it the border keeps the neutral --slean-border.
  • :empty (the empty root and the drawn icon) is widely available.

Full contract on GitHub

alert-dialog

  • <dialog>, showModal(), the top layer, ::backdrop and page inertness: Baseline widely available (newly available in 2022).
  • Invoker commands (command, commandfor): shipped in Chrome 135, Safari 26 and Firefox 144 during 2025; Baseline newly available, not yet widely available. Where they are missing, a two-line inline script (showModal() / close()) is the fallback; the package does not polyfill it. A <form method="dialog"> closes the dialog in every browser that has <dialog>.
  • closedby: Chrome 134 and Firefox 141 implement it; Safari 27 does not (checked with the system WebKit of macOS 27). There, Escape still cancels the dialog as described under Keyboard interaction; an application that must block it adds a cancel listener that calls preventDefault(), which is script and outside this contract.
  • The entrance transition uses @starting-style and the exit uses allow-discrete transitions of display (transition-behavior), both Baseline 2024. The exit also transitions overlay, which Chrome 117 and later implement and Safari 27 does not; there the exit transition runs after the dialog has left the top layer.

Full contract on GitHub

autocomplete

  • The list attribute of <input> is Baseline 2019 (widely available).
  • <datalist> as a feature is not Baseline: how options are matched (anywhere in the text or at the start), whether label is shown and whether the list appears at all differ between browsers. Where no list is shown, the field is a plain text input and the typed value is still submitted.
  • The list's appearance cannot be changed from CSS. For options rendered and styled by the page, use the combobox primitive (Tier 2).

Full contract on GitHub

avatar

  • <img> with alt, width, height and loading="lazy": Baseline widely available.
  • CSS grid, which stacks the image and the initials in one cell: Baseline widely available.

Full contract on GitHub

badge

<span> and text: Baseline widely available. Nothing else is used.

Full contract on GitHub

breadcrumb

  • <nav>, <ol> and aria-current are widely available.
  • The chevrons turn with the rotate property, Baseline 2022; without it a separator is an unturned corner.
  • :dir() is Baseline 2023; without it the chevrons point to the right under RTL as well.

Full contract on GitHub

button

<button> and :focus-visible are Baseline widely available. Invoker commands (command/commandfor) are covered by the dialog and popover contracts.

Full contract on GitHub

button-group

  • role="group", buttons and flex layout: Baseline widely available.
  • Logical corner radii (border-start-start-radius and the others): Baseline 2021, widely available.
  • The dividers between filled buttons use color-mix(): Baseline 2023, widely available. Without it, two filled buttons meet without a line.
  • :focus-visible, which raises the focused button: Baseline 2022, widely available.
  • A split button uses the popover and menu contracts: popover and popovertarget are Baseline 2024, newly available since April 2024.

Full contract on GitHub

calendar

Nothing beyond buttons, a table with ARIA grid roles, Intl.DateTimeFormat (Baseline since 2017) and, for the chevrons, :dir() (Baseline 2023). Inside a date picker, the popover features of the popover contract.

Full contract on GitHub

card

  • <article>, headings, links: Baseline widely available.
  • :has(): Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121), widely available since June 2026. The styles use it to lift other controls above a stretched link and to move its focus ring; without it the link covers them and keeps its own ring.

Full contract on GitHub

  • Scroll snap (scroll-snap-type, scroll-snap-align): Baseline 2020, widely available.
  • ::scroll-button(), ::scroll-marker, ::scroll-marker-group and :target-current: Chrome 135; not in Firefox or Safari at the time of writing. Elsewhere there are no buttons and no markers; the viewport keeps its scrollbar.
  • The tabs mode of scroll-marker-group: parsed by Chrome 151 (the oldest Chromium the tests have run), which exposes the markers as tabs in either mode; Chrome 154 exposes the default links mode as a navigation of links. An engine without the keyword drops the declaration and keeps scroll-marker-group: after.
  • Container scroll-state queries: Chrome 133; used by the styles only for the states of the buttons and markers above.
  • :dir(): Baseline 2023, widely available.

Full contract on GitHub

checkbox

appearance: none on checkboxes, :indeterminate and :checked are Baseline widely available; :user-invalid is Baseline 2023.

Full contract on GitHub

color-field

  • <input type="color"> is widely available; the picker's appearance and keyboard differ between browsers.
  • The swatch pseudo-elements are prefixed and non-standard. Where none applies, the browser's default swatch is drawn inside the styled box.
  • The HTML standard adds alpha (a transparency channel) and colorspace (limited-srgb or display-p3). Safari 27 implements both, and with either one the value becomes a CSS color such as color(srgb 1 0 0) instead of hex; Chrome 153 implements neither. The contract does not use them: without them every browser keeps the #rrggbb value.

Full contract on GitHub

combobox

  • Popover API (popover, showPopover(), hidePopover(), :popover-open, ToggleEvent): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125). Where it is unsupported the attribute is ignored and the popup renders inline; use a hidden popup for those browsers.
  • showPopover({ source }): Chrome 133 and Safari 26; not Baseline. Passed as an option, so browsers without it ignore the argument.
  • CSS anchor positioning (anchor-name, anchor-scope, position-anchor, position-area, anchor-size(), from combobox.css): Chrome 125 (anchor-scope 131) and Safari 26; not Baseline at the time of writing. Without it a hidden-toggled popup is positioned under the root with plain absolute positioning and a popover popup is centered in the top layer.
  • AbortSignal on addEventListener, Element.isConnected, scrollIntoView({ block }): Baseline widely available.
  • ARIA combobox roles and properties (combobox, aria-activedescendant, aria-autocomplete, aria-expanded, aria-controls, listbox, option, aria-selected): ARIA 1.2, widely supported by assistive technology.
  • KeyboardEvent.isComposing: Baseline widely available; keyCode === 229 covers browsers that report the composition state late.
  • The shared router: Event.composedPath(), getAttribute and ES2022 output: Baseline widely available. No transpilation to an older target is provided.

Full contract on GitHub

context-menu

  • The contextmenu event: Baseline widely available. Safari on iOS does not dispatch it for a long press, so a touch-only iPhone or iPad user cannot open the menu: offer the same actions elsewhere.
  • Popover API (showPopover()): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125).

Full contract on GitHub

date-field

<input type="date">, time and datetime-local are Baseline 2021 (widely available); month and week are not in Firefox or Safari desktop, where they fall back to a text input: validate on the server. :user-invalid is Baseline 2023.

Full contract on GitHub

date-picker

  • <input type="date"> with min, max and form submission: Baseline 2021. It holds the value and is the JavaScript-free path with the platform picker.
  • Intl.DateTimeFormat and formatToParts() (the display format and the calendar's labels): Baseline widely available.
  • Popover API (popover="manual", ToggleEvent): Baseline newly available since April 2024.
  • CSS anchor positioning (in control.css): Chrome 125 (anchor-scope 131) and Safari 26; not Baseline. Without it the popup is centered in the top layer.
  • :has() (the clear button, the range bar, the calendar's range band): Baseline 2023.
  • @media (scripting): Baseline 2023. Where it is unsupported the native and the text inputs both show.
  • ARIA 1.2 combobox with aria-haspopup="dialog" and the calendar's role="grid": widely supported by assistive technology.

Full contract on GitHub

descriptions

  • <dl>, <dt> and <dd>: widely available. <div> groups inside <dl> are valid HTML and are ignored by the accessibility tree.
  • CSS grid with repeat(auto-fill, minmax(…)), and min() and max() in the track sizes: Baseline 2020, widely available.

Full contract on GitHub

dialog

  • <dialog>, showModal(), the top layer, ::backdrop and page inertness: Baseline widely available (newly available in 2022).
  • Invoker commands (command, commandfor): shipped in Chrome 135, Safari 26 and Firefox 144 during 2025. Baseline newly available at the time of writing, not yet widely available. Where it is missing, a two-line inline script (showModal() / close()) or an opt-in compatibility module (ADR 0005) is the fallback; the package does not polyfill it.
  • closedby and requestClose() are newer than the two commands above; the contract does not depend on them.

Full contract on GitHub

disclosure

  • <details> and <summary>, the toggle event: Baseline widely available.
  • name for exclusive groups: Baseline newly available since September 2024 (Chrome 120, Safari 17.2, Firefox 130).
  • ::details-content and interpolate-size are used by the styles for animation only where supported; nothing depends on them.

Full contract on GitHub

drawer

  • <dialog>, showModal(), the top layer, ::backdrop and page inertness: Baseline widely available (newly available in 2022).
  • Invoker commands (command, commandfor): shipped in Chrome 135, Safari 26 and Firefox 144 during 2025; Baseline newly available, not yet widely available. Where they are missing, a two-line inline script (showModal() / close()) is the fallback; the package does not polyfill it.
  • closedby: Chrome 134 and Firefox 141 implement it; Safari 27 does not (checked with the system WebKit of macOS 27). There, a click on the backdrop does not close the drawer; Escape and the close action do.
  • The slide uses translate (Baseline 2022), @starting-style for the entrance and transition-behavior: allow-discrete for the exit (both Baseline 2024). The exit also transitions overlay, which Chrome 117 and later implement and Safari 27 does not; there the drawer leaves the top layer as soon as it closes, so the backdrop disappears at once and the exit slide is drawn in the page's stacking order. Under prefers-reduced-motion: reduce the duration tokens are zero and the drawer appears and disappears in place.
  • env(safe-area-inset-*) pads the edges that touch the screen; the insets are zero unless the page's viewport meta tag has viewport-fit=cover.

Full contract on GitHub

empty

  • Headings, paragraphs, links, buttons and flex layout: Baseline widely available.
  • The drawn tray uses generated content on an :empty element: Baseline widely available.

Full contract on GitHub

field

  • <label for>, aria-describedby, aria-invalid, CSS grid: Baseline widely available.
  • :has(), used to mute the label of a disabled control: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121). Where it is missing the label keeps its color.

Full contract on GitHub

file-drop

  • Dropping files on <input type="file">, which sets files and dispatches change: Baseline widely available. accept filters the picker, not a drop: a dropped file of another type is accepted by the input, so validate the type on the server (and in a change listener if the page should refuse it early).
  • Drag and drop events (dragenter, dragleave, drop): Baseline widely available.
  • Intl.ListFormat for the list of names: Baseline 2021.
  • @media (scripting), which keeps the input visible without JavaScript: Baseline 2023.

Full contract on GitHub

file-field

  • <input type="file">, multiple and accept are widely available.
  • ::file-selector-button is Baseline 2021 (widely available). Where it is missing, the browser's default button is shown inside the styled box.
  • capture is honored by mobile browsers; desktop browsers ignore it and open the file chooser.
  • :user-invalid (a required field left empty after an interaction) is Baseline 2023.

Full contract on GitHub

hover-card

  • Popover API (popover, showPopover(), hidePopover()): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125).
  • popover="hint": Chrome 133; not Baseline at the time of writing. Where the value is unknown the attribute falls back to its manual state, and the behavior hides the card itself.
  • showPopover({ source }): Chrome 133 and Safari 26; not Baseline. Without it the card still follows the trigger in the DOM order.
  • CSS anchor positioning (position-area): Chrome 125 and Safari 26; not Baseline at the time of writing. Where it is unsupported the card keeps the platform's default placement.
  • Pointer events: Baseline widely available. Touch pointers are ignored; a tap follows the link.

Full contract on GitHub

input

  • Text-like <input> types, <textarea>, ::placeholder, :read-only: Baseline widely available.
  • :user-invalid: Baseline 2023 (Chrome 119, Firefox 88, Safari 16.5). Where it is missing the field keeps its normal border after an invalid edit.
  • field-sizing: content, which makes a textarea grow with its content: Baseline newly available since June 2026 (Chrome 123, Safari 26.2, Firefox 152). Where it is missing, the textarea has the height of its rows attribute (at least three lines) and scrolls.
  • The lh unit of the three-line minimum: Baseline 2023 (Chrome 109, Safari 16.4, Firefox 120).

Full contract on GitHub

kbd

  • <kbd>: Baseline widely available.
  • :has(): Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121), widely available since June 2026. Without it a combination is drawn as one box around its keys.

Full contract on GitHub

listbox

  • ARIA listbox roles and states (listbox, option, group, aria-selected, aria-multiselectable, aria-orientation, aria-disabled): ARIA 1.2, widely supported by assistive technology.
  • The shared router: Event.composedPath(), getAttribute and ES2022 output (the packages' TypeScript target): Baseline widely available. No transpilation to an older target is provided; a consumer that needs one runs the packages through its own bundler.
  • :dir(rtl), used only to resolve dir="auto": Baseline newly available since December 2023 (Chrome 120, Safari 16.4, Firefox 49). The call is guarded in packages/primitives/src/internal/direction.ts: where the pseudo-class is unsupported, dir="auto" resolves to left-to-right and explicit dir attributes work everywhere.

Full contract on GitHub

menu

  • Popover API (popover, popovertarget, :popover-open, ToggleEvent, hidePopover()): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125). Where it is unsupported the attribute is ignored and the menu renders inline.
  • CSS anchor positioning (position-area, from popover.css, which menu.css requires): Chrome 125 and Safari 26; not Baseline at the time of writing. Where it is unsupported the menu keeps the platform's default placement (centered in the top layer).
  • ARIA menu roles and states (menu, menuitem, menuitemcheckbox, menuitemradio, group, separator, aria-checked): ARIA 1.2, widely supported by assistive technology.
  • The shared router: Event.composedPath(), getAttribute and ES2022 output (the packages' TypeScript target): Baseline widely available. No transpilation to an older target is provided; a consumer that needs one runs the packages through its own bundler.

Full contract on GitHub

menubar

  • Popover API (popovertarget, showPopover(), hidePopover(), :popover-open): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125).
  • :has() for the open item's style: Baseline 2023.
  • The ARIA menubar pattern (menubar, menuitem, none): ARIA 1.2, widely supported by assistive technology.

Full contract on GitHub

meter

  • <meter> with low, high and optimum is widely available.
  • appearance: none, which lets the stylesheet draw the track and the value, is Baseline 2022.
  • The regions are styled through pseudo-elements that are not standardized: ::-webkit-meter-bar, ::-webkit-meter-optimum-value, ::-webkit-meter-suboptimum-value and ::-webkit-meter-even-less-good-value in Chromium and WebKit; ::-moz-meter-bar with the :-moz-meter-sub-optimum and :-moz-meter-sub-sub-optimum pseudo-classes in Firefox.
  • In Chromium a percentage height on the inner pseudo-elements does not fill the element; the stylesheet gives them block-size: inherit, so the sizes reach them.

Full contract on GitHub

number-field

  • <input type="number">, stepUp() and stepDown(): Baseline widely available. step="any" cannot be stepped (the platform throws); the buttons then do nothing.
  • @media (scripting) to show the buttons only where they work: Baseline newly available since December 2023.
  • :has() for the focus ring and the invalid state on the root: Baseline newly available since December 2023.

Full contract on GitHub

otp-field

  • inputmode is Baseline 2021 (widely available). Where it is missing, the default keyboard is shown.
  • autocomplete="one-time-code" is a token of the HTML autofill standard. Safari on iOS and macOS offers a code received by SMS as a suggestion; elsewhere the suggestion depends on the browser and the keyboard, and without one the field is a plain text input. The WebOTP API (navigator.credentials.get() with otp) is a script API and not part of this contract.
  • maxlength, pattern, required and the ch unit are widely available. :user-invalid, which the stylesheet uses for the invalid border, is Baseline 2023.

Full contract on GitHub

pagination

  • Links, <nav> and aria-current are widely available.
  • The chevrons turn with the rotate property, Baseline 2022; without it a chevron is an unturned corner.
  • :dir() is Baseline 2023; without it the chevrons are not mirrored under RTL.
  • color-mix() tints the current page's border, Baseline 2023; without it the border stays transparent and the soft fill marks the page.

Full contract on GitHub

popover

  • Popover API (popover, popovertarget, popovertargetaction, :popover-open, ToggleEvent, showPopover() / hidePopover()): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125).
  • CSS anchor positioning (position-area, position-try-fallbacks): Chrome 125 and Safari 26; not Baseline at the time of writing. Where it is unsupported the popover keeps the platform's default placement (centered in the top layer).

Full contract on GitHub

progress

  • <progress> and :indeterminate are widely available.
  • appearance: none, which lets the stylesheet draw the track and the value, is Baseline 2022.
  • The value is styled through pseudo-elements that are not standardized: ::-webkit-progress-bar and ::-webkit-progress-value in Chromium and WebKit, ::-moz-progress-bar in Firefox. Each engine in the support range has one of the two; the value transition is declared on ::-webkit-progress-value only.
  • The indeterminate state is a striped background moved by a keyframe animation whose duration comes from the duration tokens. Under prefers-reduced-motion: reduce those tokens are zero and the stripes stay drawn, so the state still reads as busy.
  • :dir() is Baseline 2023; without it the stripes move toward the right under RTL as well.

Full contract on GitHub

radio-group

All features are Baseline widely available.

Full contract on GitHub

range-slider

  • <input type="range">, <output>, appearance: none and the thumb pseudo-elements (::-webkit-slider-thumb, ::-moz-range-thumb): Baseline widely available.
  • :has() for the disabled state: Baseline newly available since December 2023.
  • round() to put the start thumb on top when both meet past the middle: Baseline newly available since May 2024. Where it is unsupported the end thumb stays on top.
  • The shared router: Event.composedPath() and ES2022 output: Baseline widely available.

Full contract on GitHub

rating

  • Radios, <fieldset>, <legend>, inline SVG with fill and stroke from CSS: Baseline widely available.
  • :has(), which fills the checked star and the stars before it (label:has(~ label input:checked)) and draws the hover preview: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121). Where it is missing no star is filled; the radios keep working.
  • clip-path: inset(50%) of the visually hidden text: Baseline widely available.

Full contract on GitHub

scroll-area

  • overflow: auto, tabindex and role="region": Baseline widely available.
  • scrollbar-width: thin: Baseline 2024 (Chrome 121, Firefox 64, Safari 18.2), newly available since December 2024. Safari before 18.2 draws its default scrollbar.
  • scrollbar-color: Baseline 2025 (Chrome 121, Firefox 64, Safari 26.2), newly available since December 2025. Safari before 26.2 keeps the system colors.
  • scrollbar-gutter: stable: Baseline 2024 (Chrome 94, Firefox 97, Safari 18.2). With overlay scrollbars (the macOS default, iOS, Android) there is no gutter to reserve and nothing changes.
  • overscroll-behavior-block and -inline: contain: supported on containers with scrollable overflow since Chrome 63, Firefox 59 and Safari 16. web-features does not list the property as Baseline, because browsers differ on containers without scrollable overflow (Chrome 144 and Firefox 150 changed it; Safari has not).
  • Scroll-driven animations (animation-timeline: scroll()), which draw the edge shadows: not Baseline. Chrome 115 and Safari 26 support them, Firefox does not. The stylesheet applies them under @supports (animation-timeline: scroll()); elsewhere the area scrolls without shadows.
  • :dir(), for the right-to-left shadows: Baseline 2023, widely available.

Full contract on GitHub

segmented

  • Radios, <fieldset>, <legend>: Baseline widely available.
  • :has(), which marks the checked, focused and disabled segments: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121). Where it is missing the segments do not show the checked state; the radios keep working.

Full contract on GitHub

select

  • <select>, <option>, <optgroup>, selectedOptions, input and change events: Baseline widely available. They carry the value and the JavaScript-free path.
  • Popover API (popover="manual", showPopover(), hidePopover(), ToggleEvent): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125). Without it use a hidden popup.
  • showPopover({ source }): Chrome 133 and Safari 26; not Baseline, ignored where unsupported.
  • CSS anchor positioning (anchor-name, anchor-scope, position-area, anchor-size(), in control.css): Chrome 125 (anchor-scope 131) and Safari 26; not Baseline. Without it a hidden popup sits under the field and a popover popup is centered in the top layer.
  • :has() (the placeholder, the clear button and the disabled field in the stylesheet): Baseline 2023.
  • @media (scripting): Baseline 2023. Where it is unsupported the native select and the owned trigger both show.
  • ARIA 1.2 select-only combobox (combobox, aria-activedescendant, listbox, option, aria-multiselectable): widely supported by assistive technology.

Full contract on GitHub

separator

<hr>, role="separator" and aria-orientation: Baseline widely available.

Full contract on GitHub

skeleton

  • aria-hidden and aria-busy are ARIA 1.1 states, exposed by every current browser.
  • The shimmer is a band in the background moved by a keyframe animation whose duration comes from the duration tokens. At rest, and under prefers-reduced-motion: reduce where those tokens are zero, the band sits outside the box and the placeholder is a flat tint.
  • :dir() is Baseline 2023; without it the shimmer moves from left to right under RTL as well.

Full contract on GitHub

slider

  • <input type="range">, min, max, step: Baseline widely available.
  • Vertical form controls through writing-mode: Baseline 2024 (Chrome 124, Firefox 120, Safari 17.4). Where it is missing the vertical slider is drawn horizontally.
  • The track and thumb pseudo-elements are not standard: ::-webkit-slider-runnable-track and ::-webkit-slider-thumb in Chrome and Safari, ::-moz-range-track, ::-moz-range-thumb and ::-moz-range-progress in Firefox. Only Firefox draws the filled part of the track (::-moz-range-progress); Chrome and Safari show the thumb on an unfilled track, because filling it would need script to read the value.
  • accent-color: Chrome 93, Firefox 92, Safari 26.2; not Baseline. With data-variant="native" the platform's own slider is drawn in the accent color where it is supported; Chrome and Firefox draw that slider with the track filled up to the thumb.
  • Tick marks from a <datalist> named by list: drawn by Chrome, Firefox 109 and Safari 12.1 on their own slider only. The styled track replaces that drawing (Chrome then draws no tick marks), so tick marks need data-variant="native".

Full contract on GitHub

spinner

  • role="status" is an ARIA 1.1 live region role, exposed by every current browser; when and how it is spoken differs between screen readers.
  • The ring turns with a keyframe animation of the rotate property, Baseline 2022; without it the ring stands still. The duration comes from the duration tokens: under prefers-reduced-motion: reduce they are zero and the ring is drawn, still, while the role and the label are unchanged.
  • The track is a color-mix() tint of currentColor, Baseline 2023; without it the track is --slean-border-strong.

Full contract on GitHub

splitter

  • Pointer events and pointer capture (setPointerCapture, lostpointercapture): Baseline widely available.
  • CSS grid with calc() on a custom property: Baseline widely available.
  • touch-action: none on the handle, so a touch drag resizes instead of scrolling: Baseline widely available.

Full contract on GitHub

steps

  • aria-current="step" (ARIA 1.1) and CSS counters are widely available.
  • :has() draws the complete state and is Baseline 2023. Without it a complete step looks like an upcoming one; its text is still read.
  • The number uses alternative text for generated content (content: counter(…) / ""), Baseline 2024. A browser without it keeps the plain counter declared before it, and a screen reader may read the number with the step.
  • The check is two gradients in the indicator turned with the rotate property, Baseline 2022.

Full contract on GitHub

switch

role="switch" on a checkbox is defined by ARIA 1.2 and mapped by current screen readers. Nothing beyond the checkbox platform features is required.

Full contract on GitHub

tabs

  • ARIA tabs roles and states (tablist, tab, tabpanel, aria-selected, aria-controls, aria-labelledby): ARIA 1.2, widely supported by assistive technology.
  • The shared router: Event.composedPath(), getAttribute and ES2022 output (the packages' TypeScript target): Baseline widely available. No transpilation to an older target is provided; a consumer that needs one runs the packages through its own bundler.
  • :dir(rtl), used only to resolve dir="auto": Baseline newly available since December 2023 (Chrome 120, Safari 16.4, Firefox 49). The call is guarded in packages/primitives/src/internal/direction.ts: where the pseudo-class is unsupported, dir="auto" resolves to left-to-right and explicit dir attributes work everywhere.

Full contract on GitHub

tag

  • <button>: Baseline widely available.
  • :has(): Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121), widely available since June 2026. The styles use it only to tighten the padding beside a remove button.

Full contract on GitHub

timeline

  • <ol>, <li>, <time datetime> and generated content: Baseline widely available.
  • :has() draws the pending state: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121), widely available. Without it a pending event looks like a past one; its text is still read.

Full contract on GitHub

toast

  • Popover API (popover="manual", showPopover(), hidePopover(), :popover-open): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125). Where it is unsupported the region renders in place and toasts are still added and announced.
  • ARIA live regions (aria-live="polite"): widely supported by assistive technology. The region is shown one frame before the first toast is added, so the live list exists before its content changes.

Full contract on GitHub

toggle

  • <button> with Enter and Space activation: Baseline widely available.
  • aria-pressed (the ARIA 1.2 toggle button): announced as a toggle button with its state by screen readers on every desktop and mobile platform.
  • The shared router: Event.composedPath() and ES2022 output: Baseline widely available.

Full contract on GitHub

toggle-group

  • <button> with Enter and Space activation: Baseline widely available.
  • aria-pressed (the ARIA 1.2 toggle button) and role="group": announced by screen readers on every desktop and mobile platform.
  • The shared router: Event.composedPath() and ES2022 output: Baseline widely available.
  • :dir(rtl), used only to resolve dir="auto": Baseline newly available since December 2023 (Chrome 120, Safari 16.4, Firefox 49). Where it is unsupported, dir="auto" resolves to left-to-right; explicit dir attributes work everywhere.

Full contract on GitHub

toolbar

  • role="toolbar" and aria-orientation: ARIA 1.2, announced by screen readers on every desktop and mobile platform.
  • focusin: Baseline widely available.
  • The shared router: Event.composedPath() and ES2022 output: Baseline widely available.
  • :dir(rtl), used only to resolve dir="auto": Baseline newly available since December 2023 (Chrome 120, Safari 16.4, Firefox 49). Where it is unsupported, dir="auto" resolves to left-to-right; explicit dir attributes work everywhere.

Full contract on GitHub

tooltip

  • Popover API (popover, showPopover(), hidePopover()): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125).
  • popover="hint": Chrome 133; not Baseline at the time of writing. Where the value is unknown the attribute falls back to its manual state, and the behavior hides the content itself.
  • showPopover({ source }) for the implicit anchor: Chrome 133 and Safari 26; not Baseline. The styles also set an anchor-name on the trigger, scoped to the root with anchor-scope.
  • CSS anchor positioning (position-area): Chrome 125 and Safari 26; not Baseline at the time of writing. Where it is unsupported the content keeps the platform's default placement.
  • Pointer events (pointerover, pointerout, pointerType): Baseline widely available. Touch pointers are ignored; a long press does not show a tooltip.

Full contract on GitHub

tree

  • ARIA tree roles and states (tree, treeitem, group, aria-expanded, aria-selected): ARIA 1.2, widely supported by assistive technology.
  • :dir(rtl) for the chevron and for dir="auto": Baseline newly available since December 2023 (Chrome 120, Safari 16.4, Firefox 49).
  • The shared router: Event.composedPath(), getAttribute and ES2022 output: Baseline widely available.

Full contract on GitHub