v3.2.0
Calendar week/day views and year picker on React Aria 1.18, plus breaking Radio, Checkbox, and Switch composition changes.
Calendar gains week and day views, a reworked year picker, and range demos built on React Aria 1.18. Autocomplete adds a Virtualizer example for large option lists. Tooltip adds theme variables for global show and hide delays. The toggles (Radio, Checkbox, Switch) move to React Aria's *Field + *Button composition. This release also rolls in patch fixes for virtualized lists, grouped-field autofill, toast and fieldset behavior, and scroll and RTL styles.
⚠️ Breaking changes: Radio, Checkbox, and Switch move to an explicit *.Content composition — *.Control nests inside *.Content, the label is plain text inside *.Content (no nested <Label>), and Description/FieldError become siblings of *.Content. See Breaking Changes.
Installation
Update to the latest version:
npm i @heroui/styles@latest @heroui/react@latestpnpm add @heroui/styles@latest @heroui/react@latestyarn add @heroui/styles@latest @heroui/react@latestbun add @heroui/styles@latest @heroui/react@latestUsing AI assistants? Prompt "Hey Cursor, update HeroUI to the latest version" and your AI assistant will compare versions and apply the necessary changes. Learn more about the HeroUI MCP Server.
What's New
Calendar
Calendar and RangeCalendar gain week and day views, plus new React Aria 1.18 calendar props.
- Week / day views:
visibleDurationrenders multi-week or single-day layouts - Multiple selection: select several dates in a single
Calendar - React Aria 1.18 props:
weeksInMonthandisDateUnavailable(date, anchorDate)for ranges - Internals: month labels use React Aria's
CalendarHeading, and the year picker is rebuilt on React Aria calendar hooks
Week view:
Day view:
Multiple selection:
Autocomplete
Virtualizer support for large option lists, with docs, Storybook, and style fixes for popover sizing and listbox scroll height.
- Virtualization: Wrap
ListBoxin React Aria's<Virtualizer>insideAutocomplete.Popover(#6642) - Popover sizing: Listbox caps at
320pxwith internal scrolling; search field stays fixed above the list
Virtualization:
Table.SortableColumnHeader
Table.SortableColumnHeader renders a sortable column label with an optional ascending/descending indicator. Use it inside a Table.Column render prop and forward sortDirection (#6588).
<Table.Column allowsSorting>
{({sortDirection}) => (
<Table.SortableColumnHeader sortDirection={sortDirection}>
Name
</Table.SortableColumnHeader>
)}
</Table.Column>- Default indicator: Chevron appears when a sort direction exists
- Custom indicator: Pass
indicator, or hide it withshowIndicator={false} - Style slots:
.table__sortable-column-header+.table__sortable-column-indicator
Tooltip delay theme variables
Tooltip reads default show and hide delays from theme CSS variables (#6617):
--tooltip-delay— delay before showing a tooltip (default:1500ms)--tooltip-close-delay— delay before hiding a tooltip (default:500ms)
Override them globally:
:root {
--tooltip-delay: 700ms;
--tooltip-close-delay: 0ms;
}Individual delay and closeDelay props still override these values on specific tooltips.
Behavior change: With the default HeroUI theme, tooltip delays now default to 1500ms / 500ms instead of the previous React Aria defaults of 700ms / 0ms. Set the CSS variables or props explicitly to preserve the old timing.
Component Fixes
- Toast: ViewTransition updates are serialized in the toast queue, preventing skipped transitions and AbortError rejections when
toast.promise()swaps the loading toast for success/error feedback (#6511). - Fieldset:
disabledpropagates through React Aria Button, CheckboxGroup, Link, RadioGroup, Slider, ToggleButton, and ToggleButtonGroup contexts (#6596). - Autocomplete: Popover content is wrapped in a React Aria
Dialog, so opening the popover no longer leaves a stray focus ring on the listbox (#6627). - Tooltip: The trigger uses the
useFocusablehook instead of the<Focusable>wrapper, avoiding a false-positive "child must be focusable" warning when a tooltip is mounted inside aninertsubtree (e.g. behind an open Drawer/Modal) (#6628).
Style Fixes
- Modal / AlertDialog:
scroll-insidedialogs cap height withmax-h-full min-h-0so the body scrolls instead of overflowing (#6597). - ScrollShadow: Fade masks reserve space for visible native scrollbars via
--scroll-shadow-scrollbar-size(#6598). - Table RTL: Column separators and resize handles use logical
end-0positioning in RTL (#6606). - Link: Drops the hardcoded
text-smso links inherit font size from their parent, and.link__iconscales relative to text withsize-[0.75em]instead of a fixedsize-2(#6621). - DatePicker / DateRangePicker: Calendar popovers use
min-w-(--trigger-width)instead ofmax-w-(--trigger-width)so the calendar is at least as wide as the trigger and no longer clips horizontally (#6622). - Table: Secondary header borders and rounded corners render correctly when the table is wrapped in React Aria's
<Virtualizer>— column selectors no longer treat every virtualized column as both first and last child (#6624). - Autocomplete: The popover is constrained to the trigger width and the listbox caps its height at
320pxwith internal scrolling, so virtualized lists no longer overflow the popover (#6642). - ListBox: Replaces
flex flex-col gapwith block flow + sibling margins so React Aria's Virtualizer content height is not collapsed by flex-shrink — fixes scrollbar thumb resizing during virtualized scroll (#6636). - InputGroup / NumberField / SearchField: Browser autofill highlight lifts onto the group shell so prefix, suffix, and increment/decrement slots share the rounded highlight (#6625).
- Spinner: Uses
inline-flexwithshrink-0(instead ofrelative) so the spin animation renders correctly in non-flex layouts, and honorsmotion-reduce(#6644). - Toast: Close button uses
-top-1 -right-1on all breakpoints to align with container padding (#6574).
Dependencies
- React Aria Components:
1.17.0→1.18.0(#6586). 1.18 adds the*Field+*Buttoncomposition adopted by the toggles,CalendarHeading, andisDateUnavailable(date, anchorDate). - @internationalized/date:
3.12.1→3.12.2 - React Aria / Stately helpers:
@react-aria/*,@react-stately/*, and@react-types/sharedpatch updates
⚠️ Breaking Changes
Radio, Checkbox & Switch: explicit *.Content composition
These toggles now use React Aria's *Field + *Button composition under the hood. X.Content is now the clickable label (React Aria's *Button). Three things change:
X.Controlmoves insideX.Content— they used to be siblings.- The label is plain text inside
X.Content—X.Contentrenders the<label>element, so don't nest a<Label>component (nested<label>elements are invalid HTML). For a standaloneLabel, place it outside and link it withhtmlFor+ the toggleid. Description/FieldErrormove out as siblings ofX.Content, so they're exposed viaaria-describedbyinstead of being folded into the accessible name.
Checkbox
// v3.1
<Checkbox>
<Checkbox.Control>
<Checkbox.Indicator />
</Checkbox.Control>
<Checkbox.Content>
<Label>Accept terms</Label>
<Description>You agree to our terms</Description>
</Checkbox.Content>
</Checkbox>
// v3.2
<Checkbox>
<Checkbox.Content>
<Checkbox.Control>
<Checkbox.Indicator />
</Checkbox.Control>
Accept terms
</Checkbox.Content>
<Description>You agree to our terms</Description>
</Checkbox>Radio
// v3.1
<Radio value="a">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label>Option A</Label>
</Radio.Content>
</Radio>
// v3.2
<Radio value="a">
<Radio.Content>
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
Option A
</Radio.Content>
</Radio>Switch
// v3.1
<Switch>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Enable notifications</Label>
</Switch.Content>
</Switch>
// v3.2
<Switch>
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Enable notifications
</Switch.Content>
</Switch>Migration summary
| v3.1 | v3.2 |
|---|---|
X.Control and X.Content are siblings | X.Control nests inside X.Content |
X.Content is a layout <div> wrapping Label + help text | X.Content is the clickable <label> wrapping X.Control + label text |
Label provided via <Label> inside X.Content | Label is plain text inside X.Content (no nested <Label>) |
Description / FieldError inside X.Content | Description / FieldError as siblings of X.Content |
External label — to use a standalone Label, place it outside the toggle and link it with htmlFor + the toggle id:
<div className="flex items-center gap-3">
<Checkbox id="terms">
<Checkbox.Content>
<Checkbox.Control>
<Checkbox.Indicator />
</Checkbox.Control>
</Checkbox.Content>
</Checkbox>
<Label htmlFor="terms">Accept terms</Label>
</div>Control-only checkboxes and switches (no label, e.g. table row selection or icon switches) still need X.Content as the clickable wrapper. Wrap Checkbox.Control / Switch.Control in X.Content, omit the label, and pass an aria-label on the root.
Full per-component guides: Checkbox, Checkbox Group, Radio, Radio Group, and Switch.
Links
- Calendar Docs
- Autocomplete Docs
- Tooltip Docs
- Checkbox Docs
- Radio Group Docs
- Switch Docs
- Component Docs
- GitHub Repository
- GitHub PR #6616
Contributors
Thanks to everyone who contributed to this release!