v1.0.3
Overview
🔧 Bug Fixes
- Slider,Rating: omit aria-label when ariaLabelledby is provided (#784)
- a11y: complete non-button host polyfill for default-button controls (#751)
- AlertDialog: focus the Cancel element on open per the APG alertdialog pattern (#630)
- useBreakpoints: resolve initial state through matchMedia like update() (#730)
- Input: make the
typeprop reactive (#757) - NumberField: default accessible name on the spinbutton (#772)
- NumberField: add
ariaLabelledbyprop foraria-labelledbyon the spinbutton (#640) - Progress: only emit
aria-labelledbywhenProgress.Labelis mounted (#638) - useResizeObserver: report the content box from
immediateentries (#729) - Slider: default accessible name via locale when unlabeled (#771)
- Snackbar: stop inline position:relative from overriding portal positioning (#781)
- Group,Selection,Single,Step: complete the provider Item ARIA contract (#613)
- Rating: name the slider and drop focusable stars from examples (#773)
- Snackbar: announce toasts via persistent portal live regions (#774)
Other Commits
- Select: fix double role=option in Item examples (#775)
Patch Changes
-
#784
e697babThanks @johnleider! - fix(Slider,Rating): omit aria-label when ariaLabelledby is providedWhen both
ariaLabelandariaLabelledbyare provided,aria-labelledbynow consistently wins across Slider, Rating, and NumberField —aria-labelis omitted from the DOM. Assistive technology output is unchanged (the ARIA accessible-name algorithm already prefersaria-labelledby); only the emitted attributes are now consistent. -
#751
f6b8698Thanks @johnleider! - fix(a11y): complete non-button host polyfill for default-button controlsControls that default to
as="button"now apply a consistent host contract when the element is not a native button:role="button",tabindex0/−1, and Enter/Space activation (gated so native buttons keep browser handling only). Covers Carousel Next/Previous, Dialog and AlertDialog activators/actions/close, Pagination First/Prev/Next/Last, Popover Activator, Snackbar Close, plus gating on Collapsible/ExpansionPanel activators and Toggle. -
#630
9bd0517Thanks @sridhar-3009! - fix(AlertDialog): focus the Cancel element on open per the APG alertdialog pattern (#630)The WAI-ARIA Authoring Practices alertdialog pattern calls for initial focus to land on the least-destructive action, and the docs already stated this — but
AlertDialogContentnever actually called.focus()on the Cancel element, so focus landed wherever the browser defaulted.AlertDialogCancelnow registers its DOM element on the shared context, andAlertDialogContentfocuses it immediately after opening. -
#770
b9f69edThanks @johnleider! - fix(useBreakpoints): resolve initial state through matchMedia like update() (#730)createBreakpoints()previously derived its initial breakpoint name, band flags, andisMobilefrom aninnerWidthcomparison, whileupdate()usedmatchMedia. At fractional zoom or with classic scrollbars the two can disagree, so barecreateBreakpoints()consumers could get a wrong first paint that silently flipped band on the first resize. Initial state now resolves through the same matchMedia-based logic asupdate(). SSR and no-matchMedia environments keep the width-comparison fallback. -
#766
2a91437Thanks @sridhar-3009! - fix(Input): make thetypeprop reactive (#757)Input.Root'stypeprop was destructured once at setup and assigned as a plain
value ontoInputRootContext— every sibling field on the context is a ref or
getter, buttypewas not.Input.Controlread that frozen value, so changing
:typeonInput.Rootafter mount (the classic password reveal-toggle pattern)
never reached the rendered<input>'s DOMtypeattribute.typeis now placed on the context astoRef(() => type), andInput.Control
readsroot.type.value, matching how every other reactive context field is
consumed. -
#772
000304cThanks @johnleider! - fix(NumberField): default accessible name on the spinbutton (#772)NumberField.Controlrendered no accessible name unless alabelorariaLabelledbyprop was set, failing the axelabelrule in the documented default shape. The spinbutton now falls back to the locale-drivenNumberField.labelmessage (default: "Number"), matching the increment/decrement buttons. ProvidinglabelorariaLabelledbyoverrides the default as before. -
#640
a75e37fThanks @sridhar-3009! - fix(NumberField): addariaLabelledbyprop foraria-labelledbyon the spinbutton (#640)NumberField.Controlpreviously only supported accessible naming via thelabelstring prop, rendered asaria-label. Consumers who render a visible<label>element outside the component had no way to wire it to the spinbutton.ariaLabelledbynow flows throughNumberField.Root's context and renders asaria-labelledbyon the spinbutton, suppressingaria-labelwhen both are set to avoid a conflicting accessible name. -
#638
7ead8a0Thanks @sridhar-3009! - fix(Progress): only emitaria-labelledbywhenProgress.Labelis mounted (#638)Progress.Rootunconditionally emittedaria-labelledbypointing to a label id even when noProgress.Labelchild was mounted, creating a dangling IDREF that assistive technology could misreport.aria-labelledbyis now conditional on a label actually being present, and a newariaLabelprop covers the case where no visible label exists but an accessible name is still needed. -
#769
5457353Thanks @johnleider! - fix(useResizeObserver): report the content box fromimmediateentries (#729)With
immediate: true, the first synthesized entry'scontentRectcarried border-box dimensions in viewport coordinates, scaled by CSS transforms — every later entry from the observer reports the content box with padding offsets. The immediate entry now matches native semantics:width/heightare the content box andtop/leftare the computed padding offsets, souseElementSizereports content-box dimensions from mount instead of jumping on the first resize. -
#771
a9b7da7Thanks @johnleider! - fix(Slider): default accessible name via locale when unlabeled (#771)Slider.Thumbrenderedrole="slider"with no accessible name unlessariaLabelorariaLabelledbywas passed, failing axe'saria-input-field-namerule (serious) out of the box. The thumb now defaults itsaria-labelto the localizedSlider.labelmessage, falling back to "Slider", and skips the default whenariaLabelledbyis provided so the referenced label wins. -
#781
9bf5b4cThanks @johnleider! - fix(Snackbar): stop inline position:relative from overriding portal positioning (#781)Your positioning classes on
Snackbar.Portal(absolute,fixed, …) work again — the slot style now carries onlyzIndex. A wrapper that is stillposition: staticafter mount getsposition: relativeapplied automatically, so the stacking-context guarantee from #602 is preserved. In renderless mode, make sure the wrapper you render is positioned for the z-index to take effect. -
#633
cd59970Thanks @sridhar-3009! - fix(Group,Selection,Single,Step): complete the provider Item ARIA contract (#613)aria-selectedis only valid on roles likeoptionandtab, so the state the provider Items emitted was ignored by assistive technology. SelectionItem and SingleItem now emitrole="option", StepItem emitsrole="tab", and all four Item families (including GroupItem's existingrole="checkbox") shiptabindexplus Enter/Space (Space for checkbox) keyboard activation so the bound element is operable without consumer completion. -
#773
47342cfThanks @johnleider! - fix(Rating): name the slider and drop focusable stars from examples (#773)Rating.Rootnow exposesariaLabelandariaLabelledbyprops and always emits an accessible name on therole="slider"element — a locale-driven "Rating" default applies when neither is set. Documented examples no longer renderRating.Itemas<button>, so the slider contains no focusable descendants; items stay non-focusable spans and click-to-select is unchanged. -
#775
8191795Thanks @johnleider! - docs(Select): fix double role=option in Item examples (#775)The documented
Select.ItemandCombobox.Itemusage spread the slotattrsonto an inner element inside a non-renderless Item, so following it produced a nested duplicaterole="option"(axearia-required-parent, critical) and click handlers that fired twice. The TreeviewCue/Checkbox/Indicator/SelectAlland RadioRoot/Groupexamples had the same shape. If you copied any of these, remove the innerv-bind="attrs"spread and put your content directly in the slot — or addrenderlessso your element is the only one rendered. -
#774
77f1f59Thanks @johnleider! - fix(Snackbar): announce toasts via persistent portal live regionsSnackbar.Portalnow auto-renders a newSnackbar.Announcer— a visually-hidden polite + assertive live-region pair, empty from app start — and eachSnackbar.Rootmirrors its rendered text into the matching region on mount (urgentroutes to the assertive/alert region), so screen readers reliably announce the first toast, including on NVDA where JS-injectedrole="status"regions are not announced. Toast content renders immediately with no delay; identical consecutive messages re-announce. Pass:announcer="false"on the Portal to omit the pair or place<Snackbar.Announcer>yourself; a bareSnackbar.Rootwithout a Portal keeps its role attributes as best-effort.