v1.17.0

This release brings support for several long-awaited features, including support for expandable rows in Table, and window scrolling in Virtualizer. Expandable rows enable macOS Finder-like file trees by designating a treeColumn and rendering a chevron button within its cells. Window scrolling in Virtualizer enables virtualized collections to automatically scroll with the rest of the page. We've also added support for horizontally virtualized GridLists and ListBoxes! Finally, we significantly improved how we manage our dependencies – see below for details.

As always, many thanks to all of our contributors for all of your feedback, features, and fixes – special shout out to @nwidynski!

Dependency consolidation

React Aria Components now has 90% fewer dependencies! To accomplish this, we have consolidated all of our individual hook packages (e.g. @react-aria/button, @react-stately/table) into the react-aria and react-stately monopackages. Our packages now also support sub-path imports, e.g. react-aria-components/Button. This means easier upgrades with fewer dependencies to manage, simplified discovery of child components, faster builds, more effective tree shaking, and improved micro-frontend support.

Using sub-paths

In addition to the main package entry point, each component is now available under a sub-path. These sub-paths match the name of the main component, and include all child components used within it. For example, react-aria-components/Menu includes Menu, MenuItem, Popover, etc.

-import {Menu, MenuItem, Popover} from 'react-aria-components';
+import {Menu, MenuItem, Popover} from 'react-aria-components/Menu';

Benefits of using sub-paths include:

  • Smaller bundles without relying on tree-shaking
  • Faster builds and test runs (only need to parse code you use instead of the entire library)
  • Improved discoverability of child components. TypeScript autocomplete shows you only the components typically used together.

Our documentation has been updated to show sub-paths by default, but you can continue using the main entry point if you prefer.

Migration

If you are currently using individual hook packages such as @react-aria/button, you can migrate to monopackage imports using our use-monopackages codemod. This will use the main package entry point (e.g. react-aria), not sub-paths.

npx @react-spectrum/codemods use-monopackages --path /path/to/src

If you would like to migrate to sub-path imports, run the use-subpaths codemod.

npx @react-spectrum/codemods use-subpaths --path /path/to/src

Backwards compatibility

We have worked hard to implement this change in a backward compatible way, but there are a few things to be aware of:

  • Individual packages like @react-aria/button still work, but they now re-export from the monopackage (e.g. react-aria) instead of the other way around. You can continue using these packages, but new exports will not be added. Migrate to the mono-package using our codemod at your convenience.
  • We have gone out of our way to continue supporting old tools like webpack 4 and jest < 28, which don't support the package.json exports field and the .mjs extension. We will drop support for these tools in a future major version. We recommend upgrading as soon as possible.
  • Due to a TypeScript issue, types that were intentionally not exported were still exposed. Using these is no longer possible. If you were using any of these types, please open an issue on GitHub.
  • If you were relying on individual packages like @react-aria/button being installed by the monopackage without declaring them in your own package.json, this will no longer occur. Please add them as dependencies or migrate to using the monopackage exports.

Changelog

General Changes

Autocomplete

  • Allow moving into an Autocomplete-wrapped two-dimensional grid with ArrowLeft and ArrowRight - @LFDanLu - PR
  • Fix Autocomplete focus styles when clicking the input after virtual focus - @hanityx - PR

Collections

  • Support the full collection in SelectionManager for selectedKeys="all" behavior - @reidbarber - PR
  • Fix focus restoration in collections when deleting items - @snowystinger - PR

ColorPicker

  • Commit new color value when clicking outside the dialog - @LFDanLu - PR

ColorWheel

ComboBox

  • Add a generic type parameter to useComboBoxState for the ComboBoxState return type - @reidbarber - PR
  • Use stable selectedKeys in ComboBox to prevent an infinite loop - @reidbarber - PR
  • Accept readonly arrays for multiple-selection ComboBox values - @lixiaoyan - PR
  • Pass the selection mode generic through to ComboBox validate types - @lixiaoyan - PR
  • Allow null in validate for single selection - @lixiaoyan - PR
  • Prevent extra onSelectionChange calls - @reidbarber - PR
  • Fix required validation for multi-select ComboBox - @Nawaz-B-04 - PR
  • Add isReadOnly render props - @devongovett - PR

Date and Time

  • Fix an SSR hydration mismatch from Date.now-based private property keys - @reidbarber - PR

Dialog

Drag and Drop

  • Prevent repeated useDrop enter and exit events for portal children in drag and drop - @reidbarber - PR

FocusScope

Form

  • Expose elementType on FieldError to control the host element - @fellipeutaka - PR
  • Skip resetting form fields when the reset event is canceled - @nanto - PR

GridList

Listbox

  • Prevent modal from reopening by settling canceled animation promises - @christophmeise - PR
  • Prevent hover styles from sticking after closing a Modal with touch on Safari iOS 26 - @snowystinger - PR
  • Expose --page-width and --visual-viewport-width - @lixiaoyan - PR
  • Use an attribute presence check for data-react-aria-top-layer in MutationObserver - @lixiaoyan - PR

NumberField

  • Add isReadOnly render props - @devongovett - PR
  • Wrap commit() in flushSync when Enter is pressed so the value flushes before form submit - @tariq-r - PR
  • Preserve validation errors on blur when the value doesn't change - @snowystinger - PR
  • Fix various bugs in NumberParser - @snowystinger - PR
  • Add commitBehavior to NumberField - @will-stone - PR

RangeCalendar

  • Add commitBehavior to customize behavior when the pointer is released outside RangeCalendar - @Jiiieeef - PR, @LFDanLu - PR, PR

Select

  • Add shouldCloseOnSelect to Select - @acr92 - PR
  • Avoid an empty option in hidden Select markup - @sonsu-lee - PR

Table

  • Add support for expandable rows - @devongovett - PR
  • Fix keyboard drag and drop navigation in expandable rows - @LFDanLu - PR
  • Honor minimum width set by the Table column menu - @LFDanLu - PR
  • Prevent double focus rings in Table when clicking expand buttons - @LFDanLu - PR
  • Use min-width so Firefox respects applied Table column widths - @LFDanLu - PR
  • Automatically focus newly added rows after a drop - @LFDanLu - PR
  • Update keyboard navigation to improve navigation speed with expandable rows - @yihuiliao - PR

Tabs

  • Default shouldSelectOnPressUp to true in Tabs when an item is a link - @reidbarber - PR

TagGroup

Tree

  • Improve accessibility for TreeSection - @yihuiliao - PR
  • Export TreeEmptyStateRenderProps - @reidbarber - PR
  • Update keyboard navigation to improve navigation speed - @Sidnioulz - PR
  • Update Tree drag and drop focus behavior - @chirokas - PR
  • Fix inserting items into a child node with useTreeData under React Strict Mode - @chirokas - PR

Virtualizer

  • Automatically bind the Virtualizer visible rectangle to the window viewport - @devongovett - PR, PR
  • Lay out Virtualizer items using a consistent size - @devongovett - PR

Released packages

- @internationalized/date@3.12.1
- @internationalized/message@3.1.9
- @internationalized/number@3.6.6
- @internationalized/string-compiler@3.4.0
- @internationalized/string@3.2.8
- @react-aria/actiongroup@3.8.0
- @react-aria/aria-modal-polyfill@3.8.0
- @react-aria/autocomplete@3.0.0-rc.7
- @react-aria/breadcrumbs@3.6.0
- @react-aria/button@3.15.0
- @react-aria/calendar@3.10.0
- @react-aria/checkbox@3.17.0
- @react-aria/collections@3.1.0
- @react-aria/color@3.2.0
- @react-aria/combobox@3.16.0
- @react-aria/datepicker@3.17.0
- @react-aria/dialog@3.6.0
- @react-aria/disclosure@3.2.0
- @react-aria/dnd@3.12.0
- @react-aria/example-theme@1.1.0
- @react-aria/focus@3.22.0
- @react-aria/form@3.2.0
- @react-aria/grid@3.15.0
- @react-aria/gridlist@3.15.0
- @react-aria/i18n@3.13.0
- @react-aria/interactions@3.28.0
- @react-aria/label@3.8.0
- @react-aria/landmark@3.1.0
- @react-aria/link@3.9.0
- @react-aria/listbox@3.16.0
- @react-aria/live-announcer@3.5.0
- @react-aria/menu@3.22.0
- @react-aria/meter@3.5.0
- @react-aria/numberfield@3.13.0
- @react-aria/overlays@3.32.0
- @react-aria/progress@3.5.0
- @react-aria/radio@3.13.0
- @react-aria/searchfield@3.9.0
- @react-aria/select@3.18.0
- @react-aria/selection@3.28.0
- @react-aria/separator@3.5.0
- @react-aria/slider@3.9.0
- @react-aria/spinbutton@3.8.0
- @react-aria/ssr@3.10.0
- @react-aria/steplist@3.0.0-alpha.26
- @react-aria/switch@3.8.0
- @react-aria/table@3.18.0
- @react-aria/tabs@3.12.0
- @react-aria/tag@3.9.0
- @react-aria/test-utils@1.0.0-beta.3
- @react-aria/textfield@3.19.0
- @react-aria/toast@3.1.0
- @react-aria/toggle@3.13.0
- @react-aria/toolbar@3.0.0-beta.25
- @react-aria/tooltip@3.10.0
- @react-aria/tree@3.2.0
- @react-aria/utils@3.34.0
- @react-aria/virtualizer@4.2.0
- @react-aria/visually-hidden@3.9.0
- @react-stately/autocomplete@3.0.0-beta.5
- @react-stately/calendar@3.10.0
- @react-stately/checkbox@3.8.0
- @react-stately/collections@3.13.0
- @react-stately/color@3.10.0
- @react-stately/combobox@3.14.0
- @react-stately/data@3.16.0
- @react-stately/datepicker@3.17.0
- @react-stately/disclosure@3.1.0
- @react-stately/dnd@3.8.0
- @react-stately/flags@3.2.0
- @react-stately/form@3.3.0
- @react-stately/grid@3.12.0
- @react-stately/layout@4.7.0
- @react-stately/list@3.14.0
- @react-stately/menu@3.10.0
- @react-stately/numberfield@3.12.0
- @react-stately/overlays@3.7.0
- @react-stately/radio@3.12.0
- @react-stately/searchfield@3.6.0
- @react-stately/select@3.10.0
- @react-stately/selection@3.21.0
- @react-stately/slider@3.8.0
- @react-stately/steplist@3.0.0-alpha.22
- @react-stately/table@3.16.0
- @react-stately/tabs@3.9.0
- @react-stately/toast@3.2.0
- @react-stately/toggle@3.10.0
- @react-stately/tooltip@3.6.0
- @react-stately/tree@3.10.0
- @react-stately/utils@3.12.0
- @react-stately/virtualizer@4.5.0
- @react-types/actionbar@3.2.0
- @react-types/actiongroup@3.5.0
- @react-types/autocomplete@3.0.0-alpha.39
- @react-types/avatar@3.1.0
- @react-types/badge@3.2.0
- @react-types/breadcrumbs@3.8.0
- @react-types/button@3.16.0
- @react-types/buttongroup@3.4.0
- @react-types/calendar@3.9.0
- @react-types/card@3.0.0-alpha.44
- @react-types/checkbox@3.11.0
- @react-types/color@3.2.0
- @react-types/combobox@3.15.0
- @react-types/contextualhelp@3.3.0
- @react-types/datepicker@3.14.0
- @react-types/dialog@3.6.0
- @react-types/divider@3.4.0
- @react-types/form@3.8.0
- @react-types/grid@3.4.0
- @react-types/illustratedmessage@3.4.0
- @react-types/image@3.6.0
- @react-types/label@3.10.0
- @react-types/layout@3.4.0
- @react-types/link@3.7.0
- @react-types/list@3.3.0
- @react-types/listbox@3.8.0
- @react-types/menu@3.11.0
- @react-types/meter@3.5.0
- @react-types/numberfield@3.9.0
- @react-types/overlays@3.10.0
- @react-types/progress@3.6.0
- @react-types/provider@3.9.0
- @react-types/radio@3.10.0
- @react-types/searchfield@3.7.0
- @react-types/select@3.13.0
- @react-types/shared@3.34.0
- @react-types/slider@3.9.0
- @react-types/statuslight@3.4.0
- @react-types/switch@3.6.0
- @react-types/table@3.14.0
- @react-types/tabs@3.4.0
- @react-types/text@3.4.0
- @react-types/textfield@3.13.0
- @react-types/tooltip@3.6.0
- @react-types/view@3.5.0
- @react-types/well@3.4.0
- @spectrum-icons/color@3.6.0
- @spectrum-icons/express@3.0.0-alpha.34
- @spectrum-icons/illustrations@3.7.0
- @spectrum-icons/ui@3.7.0
- @spectrum-icons/workflow@4.3.0
- @react-aria/optimize-locales-plugin@1.2.0
- @react-aria/parcel-resolver-optimize-locales@1.3.0
- @react-aria/mcp@1.1.0
- react-aria@3.48.0
- react-aria-components@1.17.0
- react-stately@3.46.0
- tailwindcss-react-aria-components@2.1.0