# Browser support

> The versioned support policy, the Baseline features each native path depends on, what happens outside the target, and the opt-in compatibility model.

Page: https://svelte-lean.vercel.app/docs/browser-support · Markdown: https://svelte-lean.vercel.app/docs/browser-support.md · Index: https://svelte-lean.vercel.app/llms.txt

Each native path names the platform features it uses, their Baseline status and what happens without them; the packages ship no polyfills.

## Policy

- The browser target is the support of each platform feature, not a version list.
- Native paths use the feature directly; no fallback logic is mixed in.
- Compatibility code is opt-in or target-selected, never bundled silently into a native path (shipping invariant E of ADR 0005). No compatibility module exists today.
- No browser-name branching and, today, no feature detection in the packages: the stylesheets rely on CSS fallback behavior.
- The Vite plugin has no `target` option; the blueprint names one, and it is not built.
- These statements describe what is tested; they become a versioned promise from release stage 4.

## Feature table

Baseline status as each contract documents it on 2026-09-27.

| Feature (native path) | Used by | Baseline status, documented in the contract as of 2026-09-27 | Compatibility path | Without support |
| --- | --- | --- | --- | --- |
| `<dialog>, showModal(), the top layer, ::backdrop, page inertness` | Dialog | Widely available (newly available in 2022) | none exists; the package does not polyfill | No fallback is documented; the element is the base of the primitive |
| `Invoker commands (command, commandfor)` | Dialog and Popover invokers, Button | Newly available, not yet widely: Chrome 135, Safari 26, Firefox 144, shipped during 2025 | None exists; an opt-in module is named as an option in ADR 0005 | Two calls in application code (showModal(), close()); without them the dialog stays closed |
| `Popover API (popover, popovertarget, popovertargetaction, :popover-open, ToggleEvent)` | Popover, Menu (and its context menu), Menubar, Select, Autocomplete, Hint, Hover card, Toast, Date picker, the mobile navigation of this site | Newly available since April 2024: Chrome 114, Safari 17, Firefox 125 | none exists; the package does not polyfill | The attribute is ignored and the content renders inline; a menu loses its top layer and light dismiss; the select and autocomplete popups use a hidden-toggled popup instead |
| `showPopover({ source })` | Select and autocomplete popups (the trigger as the implicit anchor and invoker), Hint | Not Baseline: Chrome 133, Safari 26 | none exists; the package does not polyfill | Passed as an option that browsers without it ignore; popover="manual" needs no invoker relationship |
| `CSS anchor positioning (position-area, position-try-fallbacks)` | Popover, Menu, Menubar and Hover card placement in the stylesheet | Newly available since January 2026: Chrome 125, Safari 26, Firefox 147 | The anchor fallback of @svelte-lean/primitives: the menu, menubar and hover card behaviors load it with import() only where position-area is unsupported (Safari before 26); a plain popover opts in with @svelte-lean/primitives/popover/anchor/register | The open popup is placed next to its invoker with fixed coordinates: the same side, alignment and flip as the stylesheet, clamped into the viewport, its height capped to the room it has, following scrolling and resizing while open. With no script: centered in the top layer |
| `CSS anchor positioning (anchor-name, anchor-scope, position-anchor, position-area, anchor-size())` | Select, autocomplete and date picker popup placement in the stylesheet | Newly available since January 2026: Chrome 125 (anchor-scope 131), Safari 26, Firefox 147 | The anchor fallback of @svelte-lean/primitives, loaded with import() by the behavior only where position-area is unsupported | A hidden-toggled popup is positioned under the root with absolute positioning; a popover popup is placed under the field (at least as wide, flipped above when the bottom has no room, its height capped) |
| `KeyboardEvent.isComposing` | Autocomplete and select search (keys during an IME composition are ignored) | Widely available; keyCode 229 covers browsers that report the state late | none exists; the package does not polyfill | No fallback is documented |
| `AbortSignal on addEventListener, Element.isConnected` | Select and autocomplete session listeners (Tier 2 scoped controllers) | Widely available | none exists; the package does not polyfill | No fallback is documented |
| `<details>, <summary>, the toggle event` | Accordion, Nav groups | Widely available | none exists; the package does not polyfill | No fallback is documented; the element is the base of the primitive |
| `name on <details> for exclusive groups` | Accordion items and Nav groups that share a name | Newly available since September 2024: Chrome 120, Safari 17.2, Firefox 130 | none exists; the package does not polyfill | Siblings stay open independently |
| `::details-content, interpolate-size` | Accordion and Nav group open transitions in the stylesheet | Used only where supported; nothing depends on them | none exists; the package does not polyfill | No transition |
| `appearance: none on checkboxes, :checked, :indeterminate` | Checkbox and its switch look | Widely available | none exists; the package does not polyfill | No fallback is documented |
| `:user-invalid` | Validation styles of Checkbox, Input (every type), Select, Autocomplete, Radio group and Field | Baseline 2023 | none exists; the package does not polyfill | Native validation still works; the invalid styling does not apply |
| `role="switch" on a checkbox (ARIA 1.2)` | Checkbox, the switch look | Mapped by current screen readers | none exists; the package does not polyfill | Announced as a checkbox where the role is not mapped |
| `<button>, :focus-visible` | Button | Widely available | none exists; the package does not polyfill | No fallback is documented |
| `<fieldset>, <legend>, <input type="radio">` | Radio group | Widely available | none exists; the package does not polyfill | No fallback is documented |
| `:dir(rtl), read only to resolve dir="auto"` | Tabs, Listbox, Tree, Toggle group, Toolbar, Calendar, Splitter, Sortable and every behavior with horizontal arrow keys | Guarded in packages/primitives/src/internal/direction.ts | none exists; the package does not polyfill | dir="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 target | Run the packages through your own bundler for an older target | Without the runtime every primitive keeps its server-rendered state and native parts: tabs cannot switch, a menu opens as a plain popover, an owned select shows its native select; each contract states its own case |
| `popover="hint"` | Hint, Hover card | Not Baseline: Chrome 133 | none exists; the package does not polyfill | The value falls back to a manual popover, which the behavior hides itself |
| `Interest invokers (interestfor)` | Hover card, and the group flyouts of the Nav rail | Not Baseline: Chrome 142; not in Firefox or Safari | none exists; the package does not polyfill | The hover card behavior opens the card on pointer and focus where the attribute is not supported |
| `Customizable select (appearance: base-select, ::picker(select), ::checkmark, <selectedcontent>)` | Select | Not Baseline: Chrome 135, Safari 27; not in Firefox | none exists; the package does not polyfill | The styled closed box with the platform picker |
| `closedby on <dialog>` | Dialog: alert dialogs (none) and drawers (any) | Not Baseline: Chrome 134, Firefox 141; not in Safari 27 | none exists; the package does not polyfill | Escape 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 Dialog, its drawers and alert dialogs | Not Baseline: Chrome 117; not in Safari 27 | none exists; the package does not polyfill | The exit transition runs after the dialog has left the top layer |
| `field-sizing: content` | Input (textarea) | Newly available since June 2026: Chrome 123, Safari 26.2, Firefox 152 | none exists; the package does not polyfill | The textarea keeps the height of its rows and scrolls |
| `:has()` | Radio group (segmented), Rating, Steps, Field, Input shell, Slider (range), Select, Checkbox group styles | Baseline 2023 | none exists; the package does not polyfill | The 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, vertical | Baseline 2024: Chrome 124, Firefox 120, Safari 17.4 | none exists; the package does not polyfill | The slider is drawn horizontally |
| `Form control pseudo-elements (range thumb and track, progress value, meter regions)` | Slider and its range mode, Progress, Meter | Not standardized: -webkit- and -moz- pseudo-elements | none exists; the package does not polyfill | The platform draws the control |
| `<datalist> suggestions` | Autocomplete | Not Baseline as a feature; the list attribute is widely available | The Combobox primitive renders and styles its own options | A plain text field; the typed value is still submitted |
| `The contextmenu event` | Menu, opened by data-slean-contextmenu | Widely available; Safari on iOS does not dispatch it for a long press | none exists; the package does not polyfill | Touch-only iPhone and iPad users cannot open the menu; offer the actions elsewhere |
| `Dropping files on <input type="file">; dragenter, dragleave, drop` | File drop | Widely available; accept does not filter dropped files | none exists; the package does not polyfill | Without JavaScript the input is shown as it is and still accepts a drop |
| `scroll-target-group, :target-current` | Nav with data-slean-scrollspy (the link of the section in view) | Not Baseline: Chrome 140; not in Firefox or Safari | none exists; the package does not polyfill | No link is marked; the fragment links still work |
| `contrast-color()` | Radio group swatches (the color of the check) | Not Baseline: Safari 26, Firefox 146, Chromium | none exists; the package does not polyfill | The check is drawn in the text color on a disc of the surface color |
| `hidden="until-found" and the beforematch event` | Findable | Limited availability: Chrome and Edge 102, Firefox 139; not in Safari as far as we know | none exists; the package does not polyfill | The whole value stays hidden: the short form shows and find-in-page does not reach the whole value |
| `Pointer events, pointer capture, touch-action` | Splitter, Sortable | Widely available | none exists; the package does not polyfill | No fallback is documented |
| `Element.moveBefore()` | Sortable (a key, button or drop move of an item) | Not Baseline | none exists; the package does not polyfill | insertBefore(), and the behavior puts focus back on the control that moved the item |
| `@media (scripting)` | Select, Autocomplete, Date picker, Input (step buttons), File drop | Baseline 2023 | none exists; the package does not polyfill | The trigger and step buttons stay visible without JavaScript and do nothing |
| `round()` | Slider, range mode (which thumb is on top where both meet) | Baseline 2024 | none exists; the package does not polyfill | The end thumb stays on top |
| `color-mix()` | Hover and active fills of Button, Toggle, Badge, Alert, Progress and Pagination | Baseline 2023 | none exists; the package does not polyfill | The tinted border or track takes a neutral token |
| `Alternative text in content (content: counter() / "")` | Steps | Baseline 2024 | none exists; the package does not polyfill | A screen reader may read the step number with the step |
| `accent-color` | Slider with data-variant="native" | Not Baseline: Chrome 93, Firefox 92, Safari 26.2 | none exists; the package does not polyfill | The platform slider in its default color |
| `position: sticky` | Table sticky header | Widely available | none exists; the package does not polyfill | A normal header |

## This browser

Detected after load (requires JavaScript); the [proof page](https://svelte-lean.vercel.app/proof.md) shows the same.

| Feature | Used by | This browser |
| --- | --- | --- |
| Detection runs in the browser after load. |  |  |

## Outside the target

Invoker commands are the newest dependency. Without `command` and `commandfor`, a dialog needs two calls in application code:

`settings.svelte`

```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">Settings</h2>
	<button type="button" onclick={() => dialog.close()}>Close</button>
</dialog>
```

Branch on the feature, not the browser name:

```ts
// 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');
```

Without JavaScript, behaviors keep their server-rendered state:

| Primitive | Without the runtime |
| --- | --- |
| Tabs | The selected panel shows and cannot switch; render every panel without `hidden` for a stacked layout. |
| Menu | Opens as a plain popover; link items work; movement is Tab-based. |
| Listbox | Keeps its authored selection. |
| Select (owned) | The native select is shown and submits with the form. |
| Autocomplete (owned) | The input with its `<datalist>`: the browser shows the suggestions, the form submits what was typed. |

## Compatibility modules

None exists. ADR 0005 names an opt-in invoker-commands module and the blueprint a positioning module; neither is planned. One would be a separate entry point, with a fixture asserting that the native path excludes it (invariant E).

## Testing

- Chromium only: the local Google Chrome (version recorded in the audit and the benchmark file) and Playwright's Chromium in CI.
- Native contracts run with page JavaScript disabled in native.spec.ts.
- Firefox and WebKit run nightly; no run is recorded yet. A recorded run is a stage 2 requirement in docs/release.md. No cross-browser claim is made until then.

## Contract excerpts

The "Platform features and Baseline" section of every contract, read from the file at build time.

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). The styles pad the content's block end through it; without it the open item carries that padding. `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.
- `:has()` (Baseline 2023) gives the last item of a joined list its corners; without it the joined corners are square.

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 borders from the color; it is Baseline 2023. Without it the standard alert has no border.
- `:empty` (the empty root and the drawn icon) is widely available.

autocomplete

- `<input list>` and `<datalist>`: the `list` attribute is Baseline widely available; how the native list matches and shows options differs between browsers, which is why the owned form exists.
- Popover API: Baseline newly available since April 2024. `showPopover({ source })`: Chrome 133 and Safari 26, ignored elsewhere.
- CSS anchor positioning (`control.css`): Baseline newly available since January 2026. In an engine with anchor positioning the popup takes its content height, is capped to the room in its position area and scrolls when capped. In an older engine (Safari before 26) the behavior places a popover popup under the field, at least as wide, capped and flipped above when the bottom has no room (the anchor fallback, loaded with `import()` only there); a hidden popup sits under the field.
- `KeyboardEvent.isComposing`, `AbortSignal` on `addEventListener`: Baseline widely available.
- ARIA 1.2 combobox, `aria-activedescendant`, `listbox`, `option`: widely supported.

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.

badge

- `<span>`, text and `<button>`: Baseline widely available.
- `:has()`: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121). The styles use it only to tighten the padding beside a remove button.

breadcrumb

- `<nav>`, `<ol>` and `aria-current` are widely available.
- The chevron is drawn with `mask`, Baseline 2023; without it a separator is a filled square.
- `:dir()` (Baseline 2023) and the `scale` property (Baseline 2022) mirror the chevrons under RTL; without them the chevrons point to the right under RTL as well.

button

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

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 contained buttons use `color-mix()`: Baseline 2023, widely available. Without it, two contained 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.

calendar

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

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 stretch the link's area over the card while the other controls stay their own targets, and to move its focus ring. Without it the link's area is its own text: the link and the other controls work, a click elsewhere on the card does nothing, and the ring stays on the link.

carousel

- 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.

checkbox

`appearance: none` on checkboxes, `:indeterminate` and `:checked` are Baseline widely available; `:user-invalid` is Baseline 2023. `role="switch"` on a checkbox is defined by ARIA 1.2 and mapped by current screen readers; where it is not, the switch is announced as a checkbox.

checkbox-group

`<fieldset>`, `<legend>`, the `indeterminate` property and `:indeterminate`: Baseline widely available.

copy

- Async Clipboard API (`navigator.clipboard.writeText()`): Baseline widely available since March 2020 (Chrome 66, Firefox 63, Safari 13.1). Secure contexts only (https or localhost); the call needs a user activation in Safari and Firefox, which the click provides.
- `<button>` activation from the keyboard: Baseline widely available.

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. `<input type="datetime-local">` and `<input type="time">`: Baseline 2021 (Firefox 93, Safari 14.1).
- `Intl.DisplayNames` with `type: 'dateTimeField'` (the month and year selects' names): Baseline 2022; "Month" and "Year" where it is missing.
- `Intl.DateTimeFormat` and `formatToParts()` (the display format and the calendar's labels): Baseline widely available. `Intl.RelativeTimeFormat` (the generated buttons' names): Baseline 2020.
- Popover API (`popover="manual"`, `ToggleEvent`): Baseline newly available since April 2024.
- CSS anchor positioning (in `control.css`): Baseline newly available since January 2026 (Chrome 125, Safari 26, Firefox 147; `anchor-scope` Chrome 131). The popup takes its content height, is capped to the room in its position area and scrolls when capped. Without anchor positioning (Safari before 26) the behavior places the popup under the field, capped and flipped above when the bottom has no room (the anchor fallback, loaded with `import()` only there).
- `:has()` (the clear button, the range bar, the calendar's range band, the empty label, the presets beside the calendar): Baseline 2023. `content: attr()` (the empty label): widely available.
- `@media (scripting)`: Baseline 2023. Where it is unsupported the native and the text inputs both show.
- ARIA 1.2 combobox with `aria-haspopup="dialog"`, the calendar's `role="grid"` and `aria-pressed` on the presets: widely supported by assistive technology. The text input's `aria-controls` names the popup before it exists; it is created with that id on the first open (ADR 0011 §2.2).

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.

dialog

- `<dialog>`, `showModal()`, the top layer, `::backdrop` and page inertness: Baseline widely available (newly available in 2022).
- Invoker commands (`command`, `commandfor`): Chrome 135, Safari 26 and Firefox 144 (2025); Baseline newly 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. There a click on the backdrop does not close a drawer, and Escape still cancels an alert dialog (an application that must block it adds a `cancel` listener that calls `preventDefault()`).
- The entrance uses `@starting-style`; the exit keeps the element displayed through `transition-behavior: allow-discrete` on `display` and `overlay` (Baseline 2024; `overlay` is transitioned in Chrome 117 and later, not in Firefox or Safari 27, where the dialog closes without the exit transition). Durations are tokens, zero under `prefers-reduced-motion: reduce`.
- `position: sticky` header and footer: Baseline widely available. `env(safe-area-inset-*)` pads the edges of a drawer that touch the screen.

empty

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

field

- Constraint validation, `validationMessage`, `setCustomValidity()`, the `invalid` event: Baseline widely available. The message text is the browser's, in the browser's language.
- `<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.

file-drop

- Dropping files on `<input type="file">`, which sets `files` and dispatches `input` and `change`: Baseline widely available. `accept` filters the picker, not a drop: the behavior's check covers drops and pastes; validate on the server as well.
- `DataTransfer` constructor and assigning `input.files`: Baseline widely available.
- `URL.createObjectURL()` and `HTMLImageElement.decode()`: Baseline widely available. Each object URL is released as soon as its image is decoded (or fails to decode), so a removed, replaced or discarded item holds no blob. A Content Security Policy must allow `img-src blob:` for the thumbnails.
- `paste` on the focused input with `clipboardData.files`: Chromium and Firefox dispatch it at a focused file input; Safari dispatches no `paste` without an editable target, and nothing happens there.
- `Intl.ListFormat` (Baseline 2021) and `Intl.NumberFormat` unit style (Baseline 2021).
- `@media (scripting)`, which keeps the input visible without JavaScript: Baseline 2023. `:has()` for the area and focus styles: Baseline 2023.

findable

- `hidden="until-found"` and the `beforematch` event: Chrome and Edge 102 (May 2022), Firefox 139 (May 2025). Safari: not supported in the versions we know of; check the current status (MDN, caniuse) before relying on it. Not Baseline. Where it is missing, the value is `hidden` (`display: none`), find does not reach it, the short form shows and nothing runs. `supportsFindReveal()` tells the two apart (the `onbeforematch` handler exists).
- The same reveal runs for a fragment navigation to an element inside the value (`#id`) and for a text fragment (`#:~:text=`); the behavior treats both like a find match.
- `content: attr()` on `::after`: Baseline widely available.
- The individual `translate` property: Baseline widely available since 2022 (Chrome 104, Firefox 72, Safari 14.1).
- `document.hasFocus()`, window `focus` and `blur`: Baseline widely available.

hint

- Popover API (`popover="manual"`, `showPopover()`, `hidePopover()`): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125). The bubble is in the top layer, above an open dialog or popover. Without it the stylesheet's fixed position and z-index keep the bubble above the page, not above a modal dialog.
- `:focus-visible`: Baseline widely available (Chrome 86, Firefox 85, Safari 15.4). Where the selector throws, keyboard and pointer focus are treated alike.
- `Range.getBoundingClientRect()`: Baseline widely available. Where it measures nothing (an icon drawn as a background), the element's own box is used.
- Pointer events (`pointerover`, `pointerout`, `pointerType`): Baseline widely available. Touch pointers are ignored.

hover-card

- Interest invokers (`interestfor`, `interestForElement`, `interest-delay`): Chrome and Edge 142 (October 2025). Firefox has deferred them and WebKit's position is negative; there the fallback above runs. The attribute is still the right name: it is what the platform reads where it exists.
- Popover API (`popover`, `showPopover()`, `hidePopover()`): Baseline newly available since April 2024 (Chrome 114, Safari 17, Firefox 125).
- `popover="hint"`: Chrome 133 and Firefox 155; where the value is unknown the attribute falls back to its manual state, and the fallback hides the card itself.
- `showPopover({ source })`: Chrome 133, Safari 26 and Firefox 155; it gives the card its implicit anchor and its place in the focus order.
- CSS anchor positioning (`position-area`, `position-try-fallbacks`): Baseline newly available since January 2026 (Chrome 125, Safari 26, Firefox 147). In an older engine (Safari before 26) the behavior places the open card next to its trigger (the anchor fallback, loaded with `import()` only there); with no script `popover.css` centers it in the top layer.
- Pointer events: Baseline widely available.

input

- Every `<input>` type above, `<textarea>`, `::placeholder`, `:read-only`, `:placeholder-shown`, `stepUp()`/`stepDown()`, `::file-selector-button`: Baseline widely available.
- `:user-invalid`: Baseline 2023. Where it is missing the field keeps its normal border after an invalid edit.
- `:has()` (the shell's states): Baseline 2023.
- `field-sizing: content` (the growing textarea): Baseline newly available since June 2026; where it is missing the textarea has the height of its `rows` and scrolls.
- `@media (scripting)` (the step buttons only where they work): Baseline 2023.
- The color swatch pseudo-elements differ per engine (`::-webkit-color-swatch`, `::-moz-color-swatch`); the date and time segments are the engine's own and look different in each.

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.

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.

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): Baseline newly available since January 2026 (Chrome 125, Safari 26, Firefox 147). In an older engine (Safari before 26) the menu behavior places the open menu next to its invoker with the same side, alignment, flip and height cap (inline fixed coordinates; a module loaded with `import()` only there, which follows scrolling and resizing while the menu is open); with no script `popover.css` centers it 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.

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.

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.

nav

- `<nav>`, `<ul>`, `<details>`, `<summary>` and `aria-current`: widely available.
- `<details name>` (one group open at a time): Baseline newly available since September 2024 (Chrome 120, Safari 17.2, Firefox 130). Without it every group opens independently.
- `:has()`, which marks the group holding the current page: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121). Without it a closed group does not show that it holds the current page.
- `::details-content` (Baseline newly available since September 2025) with `interpolate-size` (Chrome 129), which animate a group's height: in Chromium; elsewhere a group opens at once.
- `scroll-target-group` and `:target-current` (`data-slean-scrollspy`): Chrome 140; elsewhere no link is marked.
- The rail's composition: the `hint` and `hover-card` contracts, invoker commands (`command="show-popover"`, Baseline 2025) and interest invokers (`interestfor`, Chrome 142).

pagination

- Links, `<nav>` and `aria-current` are widely available.
- The chevrons and the ellipsis are icons masked from `--slean-icon-*` tokens (unprefixed `mask`, Baseline 2023); the ellipsis text stays for copy and paste but is not drawn.
- `:dir()` (Baseline 2023) with the `scale` property (Baseline 2022) mirrors the chevrons under RTL; without `:dir()` they are not mirrored.
- `color-mix()` tints the current page's border, Baseline 2023; without it the border stays transparent and the soft fill marks the page.

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`): Baseline newly available since January 2026 (Chrome 125, Safari 26, Firefox 147). In an older engine (Safari before 26) the popover keeps the platform's default placement (centered in the top layer) unless the page imports the opt-in compatibility module `@svelte-lean/primitives/popover/anchor/register` (ADR 0005: never injected by `@svelte-lean/vite`). That module registers one `toggle` handler on the shared router; where anchor positioning is supported it returns after one cached `CSS.supports()` answer, and elsewhere it loads the positioner with `import()` and places the open popover next to its invoker (`popovertarget`, `commandfor` or `interestfor`), with the side, alignment, flip, viewport clamp and height cap of the stylesheet, following scrolling and resizing while it is open.

progress

- `<progress>` and `:indeterminate` are widely available.
- `appearance: none`, which lets the stylesheet draw the track and the value, is Baseline 2022.
- The bar's 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 bar 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.
- The ring is a `conic-gradient()` (Baseline 2020) masked to a ring by a `radial-gradient()` in `mask` (unprefixed `mask` is Baseline 2023); its track is a `color-mix()` tint (Baseline 2023). The indeterminate ring turns with a keyframe animation of `rotate` (Baseline 2022) whose duration is `--slean-duration-indicator`, which reduced motion slows instead of stopping.
- `:dir()` is Baseline 2023; without it the stripes move toward the right under RTL as well.

radio-group

- Radios, `<fieldset>`, `<legend>`: Baseline widely available.
- `:has()`, which marks the checked, focused and disabled segments and swatches: Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121). Where it is missing the segments do not show the checked state and the checked swatch has no ring (its check still shows); the radios keep working.
- `contrast-color()`, the swatch check's color: Safari 26, Firefox 146 and Chromium (present in the Chromium 153 the Playwright tests run); elsewhere the check sits on a surface disc.

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.

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.

select

- `<select>`, `<option>`, `<optgroup>`, `selectedOptions`, `input` and `change` events: Baseline widely available. They carry the value and the JavaScript-free path.
- Customizable select (`appearance: base-select`, `::picker(select)`, `::picker-icon`, `::checkmark`, `:open`): Chrome and Edge 135, Safari 27.0 (September 2026); Firefox behind a flag. Not Baseline; `@supports` keeps the styled closed field and the platform picker elsewhere.
- Popover API (`popover="manual"`, `showPopover()`, `hidePopover()`, `ToggleEvent`): Baseline newly available since April 2024. Without it use an authored `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`): Baseline newly available since January 2026 (Chrome 125, Safari 26, Firefox 147; `anchor-scope` Chrome 131). The popup takes its content height, is capped to the room in its position area and scrolls when capped. In an older engine (Safari before 26) a hidden popup sits under the field and the behavior places a popover popup under the field, at least as wide, capped and flipped above when the bottom has no room (the anchor fallback, loaded with `import()` only there).
- `:has()` (the placeholder, the clear button, the disabled field): Baseline 2023.
- `@media (scripting)`: Baseline 2023. Where it is unsupported the native select and the owned trigger both show.
- ARIA 1.2 combobox (`combobox`, `aria-activedescendant`, `listbox`, `option`, `aria-multiselectable`): widely supported by assistive technology.

separator

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

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.

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.
- A group: `:has()` for the disabled state and the two-thumb pointer rule, 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).
- `accent-color`: Chrome 93, Firefox 92, Safari 26.2; not Baseline. With `data-variant="native"` the platform's own slider is drawn in the current color (`data-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"`.

sortable

- Pointer events and pointer capture (`setPointerCapture`, `lostpointercapture`): Baseline widely available. `touch-action: none` on the handle, so a touch drag moves the item instead of scrolling: Baseline widely available.
- `Element.moveBefore()` (state-preserving move): not Baseline; used where present, with `insertBefore()` and a refocus otherwise.
- `role="status"` live regions: every engine and screen reader.

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.

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 and the warning are `--slean-icon-*` masks cut out of the indicator's disc (`mask-image` with `mask-composite: exclude`), Baseline 2023.

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.

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.

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.

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.

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.

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.

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.
