github ariakit/ariakit @ariakit/react@0.4.32

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, and down functions, which now scan the rendered items without copying arrays in the most common cases.
  • Fixed ComboboxItemValue highlighting 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 the data-user-value spans now cover exactly the matched characters without detaching combining marks from their base letters.
  • Fixed CompositeItem and components built on it, such as Tab and SelectItem, crashing the app with a "Maximum update depth exceeded" error when a NaN value was passed to the aria-posinset or aria-setsize props. The useStoreStateObject hook now compares snapshot values with Object.is, so the fix also covers any direct consumer of that hook.
  • Fixed CompositeItem crashing with Cannot access 'rowId' before initialization when rendered inside a CompositeRow — or a derived row component such as SelectRow or ComboboxRow — that receives the aria-posinset prop.
  • Fixed CompositeItem and components based on it, such as SelectItem and ComboboxItem, 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 Dialog and components built on it such as Popover and Menu hiding on close before the backdrop element'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 as Popover and Menu, so focusing, clicking, or right-clicking elements returned by getPersistentElements no longer closes the dialog before it has received focus, such as when it's rendered with autoFocusOnShow set to false.
  • Fixed PopoverArrow — including arrows built on it such as MenuArrow and TooltipArrow — 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 as Tooltip and Popover, to avoid leaking duplicate portal containers in React development StrictMode.
  • Fixed Portal, including components built on it such as Dialog and Popover, destroying and recreating the portal node when the portalRef prop 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 focusOnMove prop being ignored on SelectList and components built on it such as SelectPopover.
  • Fixed arrow keys on a closed Select freezing the page when multiple SelectItem components without a value prop follow the active item, and moving to an item without a value when exactly one follows it. Items without a value are now skipped correctly, including when focusLoop wraps around the list.
  • Fixed TabPanel not updating its own tabindex when a single panel is reused with a dynamic tabId pointing to the selected tab. The tabbable-children check now re-runs when the tabId changes, 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 Tab not becoming the active item on the first setSelectedId call after a SelectPopover or ComboboxPopover containing the tabs opens or toggles.
  • Fixed ToolbarContainer so 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

Don't miss a new ariakit release

NewReleases is sending notifications on new releases.