Upgrade a CSS-only tab group to the full APG tabs pattern. The baseline works
with no JavaScript: each tab is a <label> wrapping a hidden radio, and the
stylesheet reveals the matching panel through :has(input:checked), so
panels switch and server-rendered state shows correctly before (or without)
this enhancer. When it runs, it layers on the accessibility the radio group
can't express on its own: role="tablist"/tab/tabpanel, aria-selected,
aria-controls, roving tabindex, arrow/Home/End navigation with disabled-tab
skipping, and manual or automatic activation. The radios stay the single
source of truth, so CSS keeps owning panel visibility. Tabs and panels are
read live, so ones added or removed later are wired up automatically.
Selection is observable through onValueChange/hl:change and
controllable through the returned API. Markup can set
data-hl-activation, data-hl-orientation, and data-hl-default-value
on the root.
Upgrade a CSS-only tab group to the full APG tabs pattern. The baseline works with no JavaScript: each tab is a
<label>wrapping a hidden radio, and the stylesheet reveals the matching panel through:has(input:checked), so panels switch and server-rendered state shows correctly before (or without) this enhancer. When it runs, it layers on the accessibility the radio group can't express on its own:role="tablist"/tab/tabpanel,aria-selected,aria-controls, roving tabindex, arrow/Home/End navigation with disabled-tab skipping, and manual or automatic activation. The radios stay the single source of truth, so CSS keeps owning panel visibility. Tabs and panels are read live, so ones added or removed later are wired up automatically. Selection is observable throughonValueChange/hl:changeand controllable through the returned API. Markup can setdata-hl-activation,data-hl-orientation, anddata-hl-default-valueon the root.