ProComponents, templates & AI tooling
HeroUI
27.7k

v3.2.0

Calendar week/day views and year picker on React Aria 1.18, plus breaking Radio, Checkbox, and Switch composition changes.

June 15, 2026

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@latest
pnpm add @heroui/styles@latest @heroui/react@latest
yarn add @heroui/styles@latest @heroui/react@latest
bun add @heroui/styles@latest @heroui/react@latest

Using 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: visibleDuration renders multi-week or single-day layouts
  • Multiple selection: select several dates in a single Calendar
  • React Aria 1.18 props: weeksInMonth and isDateUnavailable(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 ListBox in React Aria's <Virtualizer> inside Autocomplete.Popover (#6642)
  • Popover sizing: Listbox caps at 320px with 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 with showIndicator={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: disabled propagates 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 useFocusable hook instead of the <Focusable> wrapper, avoiding a false-positive "child must be focusable" warning when a tooltip is mounted inside an inert subtree (e.g. behind an open Drawer/Modal) (#6628).

Style Fixes

  • Modal / AlertDialog: scroll-inside dialogs cap height with max-h-full min-h-0 so 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-0 positioning in RTL (#6606).
  • Link: Drops the hardcoded text-sm so links inherit font size from their parent, and .link__icon scales relative to text with size-[0.75em] instead of a fixed size-2 (#6621).
  • DatePicker / DateRangePicker: Calendar popovers use min-w-(--trigger-width) instead of max-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 320px with internal scrolling, so virtualized lists no longer overflow the popover (#6642).
  • ListBox: Replaces flex flex-col gap with 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-flex with shrink-0 (instead of relative) so the spin animation renders correctly in non-flex layouts, and honors motion-reduce (#6644).
  • Toast: Close button uses -top-1 -right-1 on all breakpoints to align with container padding (#6574).

Dependencies

  • React Aria Components: 1.17.01.18.0 (#6586). 1.18 adds the *Field + *Button composition adopted by the toggles, CalendarHeading, and isDateUnavailable(date, anchorDate).
  • @internationalized/date: 3.12.13.12.2
  • React Aria / Stately helpers: @react-aria/*, @react-stately/*, and @react-types/shared patch 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.Control moves inside X.Content — they used to be siblings.
  • The label is plain text inside X.ContentX.Content renders the <label> element, so don't nest a <Label> component (nested <label> elements are invalid HTML). For a standalone Label, place it outside and link it with htmlFor + the toggle id.
  • Description/FieldError move out as siblings of X.Content, so they're exposed via aria-describedby instead 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.1v3.2
X.Control and X.Content are siblingsX.Control nests inside X.Content
X.Content is a layout <div> wrapping Label + help textX.Content is the clickable <label> wrapping X.Control + label text
Label provided via <Label> inside X.ContentLabel is plain text inside X.Content (no nested <Label>)
Description / FieldError inside X.ContentDescription / 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.

Contributors

Thanks to everyone who contributed to this release!

On this page