Faster keyboard navigation on composite widgets
Moving through items with arrow keys no longer re-renders the Composite component itself when using roving tabindex.
This reduces the scripting cost of each keystroke on large collections and benefits everything built on composite widgets, such as Menu, Combobox, Toolbar, and Tab.
Fixed Command stuck pressed state when losing focus mid-press
When rendering a non-native element (such as render={<div />}), the Command component — and components built on it, such as Button, Checkbox, CompositeItem, and their derivatives — now clears its pressed state (data-active) when the element loses focus while Space is held, mirroring how native buttons cancel the Space activation when they lose focus before the keyup.
Additionally, a Space keyup bubbling up from a focused child no longer dispatches a synthetic click on the element, and calling event.preventDefault() in a custom onKeyUp handler no longer leaves the element stuck looking pressed.
PopoverArrow box-shadow ring detection
Fixed PopoverArrow, including components built on it such as TooltipArrow, MenuArrow, and HovercardArrow, to draw the popover's box-shadow ring for any positive ring width. Previously, widths whose text contained the digit 0, such as 10px or 0.5px from the Tailwind ring-[10px] and ring-[0.5px] utilities, were not detected, and the arrow rendered with no stroke at all.
The arrow stroke now also matches the ring color instead of the popover's inherited text color, so the arrow blends into the outline. This includes inset rings and rings without an explicit color, which default to currentColor following CSS.
Radio onChange event on arrow-key selection
Selecting a native Radio or FormRadio with arrow keys now delivers a real change event with event.target.checked already set to true, matching pointer and Space selection. Previously, the handler received the focus event while checked was still false, which silently broke handlers gated on event.target.checked.
Since arrow-key selection now replays the browser's native activation, onClick handlers also fire when a native radio is selected with arrow keys, matching native radio group behavior.
Other updates
- Improved the performance of the composite store's
next,previous,up, anddownfunctions, which now scan the rendered items without copying arrays in the most common cases. - Fixed
ComboboxItemValuehighlighting the wrong characters for item values whose Unicode normalization changes the string length, such as Hangul, kana with dakuten, and decomposed (NFD) strings. Matching remains diacritic-insensitive, and thedata-user-valuespans now cover exactly the matched characters without detaching combining marks from their base letters. - Fixed
CompositeItemand components built on it, such asTabandSelectItem, crashing the app with a "Maximum update depth exceeded" error when aNaNvalue was passed to thearia-posinsetoraria-setsizeprops. TheuseStoreStateObjecthook now compares snapshot values withObject.is, so the fix also covers any direct consumer of that hook. - Fixed
CompositeItemcrashing withCannot access 'rowId' before initializationwhen rendered inside aCompositeRow— or a derived row component such asSelectRoworComboboxRow— that receives thearia-posinsetprop. - Fixed
CompositeItemand components based on it, such asSelectItemandComboboxItem, leaving DOM focus stuck on the item with virtual focus enabled when the item received focus before the composite element was available, instead of redirecting focus to the composite element. - Fixed
Dialogand components built on it such asPopoverandMenuhiding on close before thebackdropelement's exit transition ends: the backdrop's fade-out was skipped entirely when only the backdrop was animated, and cut short when its transition was longer than the panel's. - Fixed
Dialog, including components built on it such asPopoverandMenu, so focusing, clicking, or right-clicking elements returned bygetPersistentElementsno longer closes the dialog before it has received focus, such as when it's rendered withautoFocusOnShowset tofalse. - Fixed
PopoverArrow— including arrows built on it such asMenuArrowandTooltipArrow— detaching from the anchor in RTL contexts when the popover flips or otherwise changes placement while open. - Fixed
Portal, including components built on it such asTooltipandPopover, to avoid leaking duplicate portal containers in React development StrictMode. - Fixed
Portal, including components built on it such asDialogandPopover, destroying and recreating the portal node when theportalRefprop changes identity, such as when passing an inline callback. The ref now re-fires against the same portal node, so the portal content is no longer remounted on parent re-renders. - Fixed the
focusOnMoveprop being ignored onSelectListand components built on it such asSelectPopover. - Fixed arrow keys on a closed
Selectfreezing the page when multipleSelectItemcomponents without avalueprop follow the active item, and moving to an item without avaluewhen exactly one follows it. Items without avalueare now skipped correctly, including whenfocusLoopwraps around the list. - Fixed
TabPanelnot updating its owntabindexwhen a single panel is reused with a dynamictabIdpointing to the selected tab. The tabbable-children check now re-runs when thetabIdchanges, so the panel joins the tab sequence when the newly selected tab's content has no tabbable elements and leaves it when the content has one. - Fixed
Tabnot becoming the active item on the firstsetSelectedIdcall after aSelectPopoverorComboboxPopovercontaining the tabs opens or toggles. - Fixed
ToolbarContainerso composing Enter keydowns in nested text fields don't cancel IME commits or move focus back to the container. - Updated dependencies:
@ariakit/react-components@0.3.1