Repository navigation
@chassis-ui/react v0.3.0
Minor Changes
-
c35c029: Add
Alert, chassis-css's alert dialog: a<dialog role="alertdialog">opened as a modal dialog
for a decision the flow can't continue without, such as confirming a destructive action. Compose
AlertIcon,AlertBodywithAlertTitle,AlertCodeandAlertText, andAlertFooterwith
the actions.AlertCancelis the least destructive action: it closes the alert and has focus
when the alert opens. Open state works likeModal's (visible,defaultVisible,
onVisibleChange,onClose), but a backdrop click and Escape don't close an alert unless
backdropandkeyboardallow them. The title names the alert and the code and text describe
it. Also a subpath:@chassis-ui/react/alert.Modal,DrawerandAlertnow focus an element withdata-autofocuswhen they open. The docs
saidautofocusworked, but React writes noautofocusattribute in a page rendered in the
browser, so the dialog itself got focus instead. A closingModal,DrawerorAlertalso no longer
takes focus back from a dialog opened from it, and after a chain of them focus returns to the
element that opened the first. -
01309f3:
ContextMenu: the region a context menu belongs to. A right-click (contextmenu, so Ctrl+click on
macOS too), a long press by a finger or a pen, or Shift+F10 and the context menu key on a focused
element inside it open the menu at that point, in place of the browser's own. The menu is a
MenuListamong the region's children, withMenu's items, headers, dividers, submenus and
itemsdata, portaled to the body or to the open<dialog>around the region, and positioned with
its start corner at the pointer, flipped above it when there is no room below. The first item takes
focus on open; Escape and a click on an item close the menu and return focus to the element that
had it; a press outside closes it too. The region is a polymorphic element (component,
asChild) and takesvisible/defaultVisible/onVisibleChange,onShow/onHide,autoClose
asMenu's, anddisabled, which leaves the region to the browser.MenuListno longer writesaria-labelledbywhen it is given anaria-labelof its own, which
that attribute would have outranked, nor when there is no trigger to point at. -
d60c013:
GridandGridItemare the grid of the library, on the CSS grid of@chassis-ui/css0.6.Row
andColare deprecated with the flexbox grid they render.Breaking:
@chassis-ui/css0.6 is required (the peer range is>=0.6.0 <0.7.0). The components
below render classes that 0.5 does not have, so on 0.5 aGridItemis one track wide and a
Skeletonwith aspanhas no width. In css 0.6 the gap of a grid with nogapis the gutter of
the breakpoint, from 0.5rem on a phone to 3rem on the widest screens, where it was 1.5rem.GridItemrenderscol-span-{n}andcol-start-{n}, where it renderedg-col-{n}and
g-start-{n}.span="full"spans the row (col-span-full): an item with nospanis one track
wide, so a column that stacks below a breakpoint isspan="full" responsive={{ md: { span: 6 } }}.
start="auto"returns an item to the flow at a wider breakpoint.rowSpanandrowStartplace
it on the rows (row-span-{n},row-start-{n}).responsivetakes all four.Gridtakesresponsive, asFlexdoes:columnsat a breakpoint rendersgrid-cols-{n}(1
to 12) andgaprendersgap-{token}. TheGridLayouttype is exported.- Breaking:
columnsfrom 1 to 12 renders thegrid-cols-{n}class onGrid, where it set
--cx-grid-columns. The grid has the same columns. A grid nested in it no longer inherits the
count, as it did through the custom property: aGridinside<Grid columns={1}>has its own
12 columns again. A count with no class (13 and up) still sets--cx-grid-columns. - Breaking: a
Spacingtoken ingaprenders thegap-{token}class onGridand on asubgrid
item, where it set--cx-grid-gapto the token's custom property. The gap is the same. A grid
nested in it no longer inherits it, since a class is not inherited as the custom property was:
give a nested grid, and asubgriditem, thegapof its own. A raw value (gap="1rem") still
sets--cx-grid-gap. Grid filltakesmin, the minimum column width (--cx-grid-min), below which the children
wrap. Its rawgapsets--cx-grid-gap, where it set--cx-gap.SkeletonandSkeletonLoadertake the samespan,responsiveandspansvalues and render
width utilities where they rendered the classes of the flexbox grid:w-{n}/12for a count,
w-100for 12,w-autofor'auto'andflex-fillfortrue. The widths are the same. At a
breakpoint, 12 and'auto'render{breakpoint}:w-100and{breakpoint}:w-auto, which
@chassis-ui/css0.6.0 does not have: inresponsive, use a count up to 11, ortrue.RowandColstill render.rowand.col-*and work as before. They are marked
@deprecatedand warn once in development.@chassis-ui/cssremoves its flexbox grid in 0.7,
and they go with it.
To move from
RowandCol:Before After <Row><Grid>, with noContainerneeded around it<Col span={4}><GridItem span={4}><Col span={12}><GridItem span="full"><Col span={12} responsive={{ md: { span: 6 } }}><GridItem span="full" responsive={{ md: { span: 6 } }}><Col span={4} offset={2}><GridItem span={4} start={3}>, exact for the first item of a row<Col order="first"><GridItem className="order-first"><Row>with bare<Col>s, equal columns<Grid fill>with plain children<Row cols={3}>with bare<Col>s<Grid columns={3}>with plain children<Row cols={1} responsive={{ md: { cols: 3 } }}><Grid columns={1} responsive={{ md: { columns: 3 } }}><Row gutter="md"><Grid gap="md">gutterX,gutterYclassName="column-gap-{token}",className="row-gap-{token}"<Col span="auto">, columns as wide as their content<Flex gap="md">with plain children -
074f61f:
DatePickerandDateRangePickertake a time:granularity(day,hour,minute,second)
adds the time segments to the field, and the value becomes aCalendarDateTime, or a
ZonedDateTimefrom a zonedvalue,defaultValueorplaceholderValue. AlsohourCycle,
hideTimeZone,placeholderValueandshouldForceLeadingZeros, as onTimeField. Picking a day
in the calendar keeps the time; an empty field takes the time and zone ofdefaultValue(single
selection only), elseplaceholderValue, else midnight with no zone, so a controlled zoned value
needs a zonedplaceholderValueto stay zoned once cleared. The hidden input ofnameholds the
date and time, and aZonedDateTime's zone.Both pickers now show a value outside
minValue/maxValue, on an unavailable date, or a range
that ends before it starts as invalid, withinvalidFeedback, asTimeFielddoes;validgives
way to it.invalidnow also reaches the segments asaria-invalid.CalendarandRangeCalendartakedefaultFocusedValue, the date they first show; the pickers
pass theirplaceholderValue. Their "today" is the value's time zone's for aZonedDateTime, as
react-aria's label for the day already was, rather than always the browser's.A field given
invalidFeedbackorvalidFeedbackis wrapped in its.form-fieldbefore the
feedback shows, not only once it does: moving the control into the wrapper remounted it, and a
TimeFieldtyped out of its range lost focus. The ", " between a date and its time renders as
plain text, like the space before AM/PM; a date's own literals keep their spacing. -
5d6e2e8: Add
Divider: the line chassis-css draws with its reboot's<hr>, and with.vrwhen
orientation="vertical". Children become a label in the line ("or" between two ways to sign in),
placed withlabelPlacement(start,center,end), which names the separator for screen
readers. An<hr>by default, a<div role="separator">when vertical or labelled;component
andasChildrender any other element as the separator. Also a subpath:@chassis-ui/react/divider.The label, the vertical line and the line on elements other than
<hr>are in
@chassis-ui/react/style.css. The color, thickness, opacity and margin of the line, and the color,
size and gap of the label, are custom properties (--cx-divider-color,--cx-divider-size, ...),
defaulting to chassis-css's values for<hr>and.vr; a divider inside a menu takes the menu's.Also:
@chassis-ui/react/style.cssnow opens with chassis-css's layer order, so it works imported
before or after chassis-css's stylesheet. And underasChild, an element's ownaria-labelkeeps
naming it where the component would name it witharia-labelledby. -
df988a6: Add
NavOverflow, chassis-css's nav overflow (the Priority+ pattern): wrap aNav, aNavbarNav
or theTabListof aTabs, and the items that don't fit its width move into a menu behind a
"More" toggle. It follows the width of its container, measures before the browser paints, and
keeps the items in their order. The active item and the item that has focus stay in the list, and
so does an item that isn't a link. A link in the menu is aMenuItemwith the link's own props,
soonClickand a router link given withasChildkeep working there. Options as chassis-css's
plugin names them:threshold,collapseBelow,moreText,moreIcon,iconPlacement,
menuPlacement, plusmoreLabel,menuContainerandonOverflow. Also a subpath:
@chassis-ui/react/nav-overflow.The server renders every item; see "What the server renders" in the SSR guide for the first paint.
With it:
NavItemandTabtakekeepVisible, to keep an item out of the menu.NavItemPropsis
exported.Tabsfinds itsTabListinside the element that holds it, so the list can sit in a
NavOverflowor in an element of your own beside other controls.MenuToggletakescaret={false}for a toggle without the caret, and keeps atabIndexit is
given, which react-aria's used to replace.IconProvider'siconstakesmore, the toggle's icon.
-
8f100c9:
NavandTabListtakevariant="segments", the segmented control that@chassis-ui/css0.6
made of the pills: it renamed.nav-pillsto.nav-segmentsand restyled it, with the colors,
padding, corner radius and shadow of the design tokens.Breaking:
variant="pills"rendersnav-segments, where it renderednav-pills, a class css 0.6
no longer has. It is deprecated and warns once in development: writevariant="segments". A
selector of your own on.nav-pillsno longer matches, and the--cx-nav-pills-*custom
properties are--cx-nav-segments-*in css 0.6.css 0.6 also renamed
.card-header-pillsto.card-header-segments, a class an app writes itself
on aNavin aCardHeader:<Nav variant="segments" className="card-header-segments">.Also new on
NavandTabList:size="sm"andsize="lg", the nav sizes of css 0.6 (.nav.sm,.nav.lg), which scale the
padding, gap, icon and font of the links in every variant.variant="underline"(.nav-underline), which underlines the active link.
-
8ca316e: Add
NumberField, a text input for numbers on react-aria'suseNumberField: increment and
decrement buttons, the arrow keys, Page Up and Page Down, Home and End forminandmax, and
step, which a typed value snaps to.formatOptions(Intl.NumberFormat's) shows decimals,
percents, currencies and units in the locale's format whilevaluestays a number;onChange
gets the number,NaNwhen empty.label,helpand the validation props as onTextInput, and
adornStart/adornEnd. Withname, a form receives the number.stepButtons={false}leaves the
buttons out; their icons areIconProvider's newincrementanddecrement, orincrementIcon
anddecrementIcon. Also a subpath:@chassis-ui/react/number-field.The step buttons' styles are in
@chassis-ui/react/style.css, and read.form-input's own
padding, border and colors. On a phone, the server's HTML asks for the numeric keyboard, and the
field picks the one with the keys it needs (a minus sign, a decimal separator) once hydrated. -
71f2d2b: Every component that takes
hreffollows one rule: it renders an<a>whenhrefis set, unless
componentorasChildchose the element, andhrefreaches only an element that can take it.ListItemandStepperItemrender an<a>forhrefalone. They used to stay an<li>with an
hrefattribute and no link.ListandStepperrender a<div>around such an item in place
of the<ul>or<ol>, as they already did forcomponent="a".CloseButtonrenders an<a>forhrefalone. It used to drophrefunlesscomponent="a"was
passed as well.MenuItemwithouthrefrenders a<button type="button">, which chassis-css styles as
.menu-itemtoo. It used to render an<a>with nohref, which can't take focus.- A router link passed as
componentgetshreffromPaginationItemandCloseButton. They used
to drop it. - A router link passed as
componentwithhref(orto) is handled as a link, as it already was
as theasChildelement. When disabled, it getsaria-disabledandtabindex="-1"and its click
is blocked; it used to stay focusable and navigate, andButton,AvatarandCloseButtonwrote
an invaliddisabledattribute onto the<a>.ListItemgetslist-action,CloseButtonits
classes, andListandStepperrender a<div>around such an item. hrefis no longer written onto an element that can't take one:component="div"or
component="button"onButton,Chip,Avatar,NavbarBrand,Linkand the components built
on it. The component warns in development instead.Navno longer putsrole="navigation"on its<ul>, which took away the list's semantics. Put
a<nav>around it for the landmark.NavItemrenders itsNavLinkforcomponentorasChildas well ashref. Without a link it
no longer writesactive,disabledorcomponentonto its<li>as attributes.Avatarno longer writes adisabledattribute onto its<span>.MenuTogglewithhrefrenders<a role="button">without atype, andcomponent="button"
renders a<button>without a redundantrole.
The ref types of
ListItem,StepperItem,CloseButtonandMenuItemaccept the elementhref
switches to, asButton's already did. -
9ce6aba: Every component that shows and hides takes its state under three props:
visibleis controlled,
defaultVisibleis the initial state of an uncontrolled component, andonVisibleChange(visible)
reports each change the component asks for.Popover,Tooltip,Menu,Modal,Drawer,
Toast,Notification,DatePickerandDateRangePickertake all three, and a state setter fits
the callback as it is:visible={open} onVisibleChange={setOpen}.Breaking:
visibleonPopover,Tooltip,Menu,ToastandNotificationis now controlled.
It used to be copied into the component's own state whenever it changed, so the component still
opened and closed itself in between and a parent could not hold it closed. Now the component
shows and hides only whenvisiblechanges; its trigger, the Escape key, a click outside, a close
button and theautohidetimer are requests, reported toonVisibleChange. TypeScript does not
flag the difference, so check each use:visibleas the initial state (<Popover visible>,<Toast visible autohide>): use
defaultVisible.visible={open}withonShowandonHidesettingopen: useonVisibleChange={setOpen}.
onShowandonHidefire when the component has shown or hidden, which undervisiblehappens
only after the state changed.<Toast visible={open} onClose={() => setOpen(false)}>, and the same onNotification: use
onVisibleChange={setOpen}.onClosefires after the toast has hidden.<Tooltip visible onShow={...}>:onShowno longer fires for a tooltip that is shown when it
mounts, as it never did onPopoverandMenu. It reports a change, and there was none.
In development, a request that is dropped because
visibleis set and there is no
onVisibleChangewarns once.ModalandDrawerbehave as before:visiblewithonCloseis
still complete, anddefaultVisibleadds a dialog that is open at first and closes itself.
Collapseis unchanged and takesvisibleonly.Also in this release:
DatePickerandDateRangePickertakevisible,defaultVisibleandonVisibleChange.
isOpen,defaultOpenandonOpenChangestill work, are deprecated, and warn in development.PopoverandTooltippass every other attribute to their panel:className,style,id,
data-*, event handlers. They forward a ref to it. They used to acceptaria-labeland
aria-labelledbyonly (Popover) or nothing (Tooltip). A calleridis the one the trigger's
aria-controlsoraria-describedbypoints to.MenuToggle'svariantis typed asButton's, sovariant="link"is accepted (#38).
Breaking:variant="solid"no longer type-checks, as onButton, where it is the look with no
variant.ToastContent, the options ofaddToast, covers everyToastprop thatToasterpasses on:
role,closeButton,closeLabel,message,title,icon,timeandfooterare new
(#39).childrenis optional, so a toast can be queued from the shorthand props alone.
-
c4d2adb: Declare
@chassis-ui/cssas a peer dependency (>=0.6.0 <0.7.0), so a mismatched version warns
at install instead of silently collapsing spacing after a token rename.Breaking:
reactandreact-domnarrow from>=18to^19.0.0. React 19 is the version the
package is tested on. On React 18, part of its own test suite and its type check fail.The build now ships source maps with the original TypeScript embedded, so stack traces and
debuggers show the source instead of minified code.src/is no longer published, since the maps
carry it. Tarball: 565 files, 330.6 kB packed, 1,261 kB unpacked before; 356 files, 361.9 kB
packed, 1,391 kB unpacked after. -
badd481: Three additions for server-rendered apps and accessible markup:
Portalrenders its children intodocument.bodyor acontaineryou give, and renders
fallback(nothing by default) on the server and during hydration, so a server-rendered page
hydrates without a mismatch. It is what the library's own overlays use.useHydrated()isfalseon the server and during hydration,trueafter, for rendering what
only the browser knows.VisuallyHiddenrenders chassis-css's.visually-hidden(a<span>by default, with
componentandasChild), or.visually-hidden-focusablewithfocusable, for a skip link.
Each is also a subpath:
@chassis-ui/react/portaland@chassis-ui/react/visually-hidden. -
2aac59e: Every component that renders an element of its own now forwards a ref.
Autocomplete: to the toggle, the.comboboxelement, asComboboxdoes.PasswordStrength: to the meter. It reached it before only by accident, and TypeScript rejected
it.FormField: to the.form-fieldelement.nullwhile the field renders its children bare,
with nolabel,help, feedback orclassName.SkeletonLoader: to the first generated skeleton whileloading,nullonce the content
shows.
TooltipandPopoverrender their trigger the wayasChildrenders a child. A trigger's own
aria-describedbynow keeps the tooltip's description beside it instead of losing to it, and a
trigger that isn't exactly one element renders as it is, with a development warning, instead of
throwing. The trigger's own handlers now run after the component's, as underasChild.Under
asChild, a child's ownaria-describedbyadds to the component's instead of replacing it. -
4a2bf4c: Add
Scrollspy, chassis-css's scrollspy: wrap a navigation whose links point to sections of the
page, and the link to the section being read gets.activeandaria-current="true", in the
viewport or in an element that scrolls (root). The links areLinkand the components built on
it (NavLink,NavItem, an interactiveListItem,MenuItem), withhrefon the component or,
underasChild, on its element. The link a nestedNavfollows and the toggle of a menu are
marked too, as the plugin marks them. Options:rootMargin,smoothScroll(instant under
reduced motion), andonActiveChangefor the plugin'sactivateevent. AlsouseScrollspy(ids, options), which returns the active section's id, and a subpath:@chassis-ui/react/scrollspy.The active section is the last whose top has passed a line near the bottom of the scrolling area,
or the first while it is still in view at the top: the same position always marks the same link,
whichever way the page scrolled. Sections rendered later are found without arefreshcall. The
server marks no link; see "What the server renders" in the SSR guide. -
bae995a:
SearchField: a native<input type="search">on react-aria'suseSearchField, in chassis-css's
input adorn shape, a.form-input.search-fieldaround a.ghost-inputwith a search icon at its
start and, while there is a value, a clear button. The button and the Escape key empty the field
and keep focus on the input; Escape in an empty field reaches the dialog or menu around it.
onSubmitreceives the value on Enter, with any modifier key and in a read-only field too, instead
of the form submitting; without it the field submits its form undername. It takeslabel,
help, the validation props,size,disabledandreadOnlylike the other form fields,
searchIcon(falseleaves it out),clearIconandclearAriaLabel. Two icon purposes join
IconProvider'sicons:search(search-outline) andclear(xmark-outline).Its styles, in
@chassis-ui/react/style.css, hide the browser's own clear button, and give the clear
button the field's icon color and the close button's idle and hover opacity
(--cx-close-button-idle-opacity,--cx-close-button-hover-opacity). A field disabled by its
<fieldset>hides the button too. -
1387cde: Add
TimeField, a time of day on react-aria'suseTimeField: one editable segment per unit, as
the field ofDatePickerrenders a date, typed into or stepped with the arrow keys, in the
locale's format (12 or 24 hours, the order of the units, right to left).granularity(hour,
minute,second),hourCycle,minValue/maxValue(a time outside shows the field invalid
with itsinvalidFeedback),placeholderValue,hideTimeZone,shouldForceLeadingZeros.
Values areTime,CalendarDateTimeorZonedDateTime; withname, a form receives an ISO 8601
time, and a form reset restoresdefaultValue.label,helpand the validation props as on the
other fields. Also a subpath:@chassis-ui/react/time-field.The segments' styles are the date pickers', in
@chassis-ui/react/style.css. The date pickers'
segments are laid out inline now, so a time in a right-to-left locale reads left to right, and a
read-only segment no longer writescontenteditable="false"besidearia-readonly. -
5457b3d:
TreeandTreeItem: a tree of expandable items, on react-aria-components'Tree. Items are
written as nestedTreeItemelements, or rendered from data withitemsand a render function on
the tree and on any item, asDataGrid's body is. An item with child items has a chevron that
expands and collapses it, as the arrow keys do;expandedKeys/defaultExpandedKeys/
onExpandedChangehold which items are expanded, and the server renders the expanded ones.
selectionModeallows one item or several to be selected, with a checkbox per item for multiple
selection (checkboxesturns it on or off), andselectedKeys/onSelectionChange,
disabledKeys,disallowEmptySelectionandselectionBehavioras onDataGrid. Enter, or a
click in a tree with no selection, callsonAction, andrenderEmptyStatefills an empty tree.
The keyboard
moves between items with the arrow keys, Home and End, and finds one by typing its text.Tree.scssstyles the rows, indist/style.css: indentation per level (--cx-tree-indent), the
chevron, and the hover, selected and disabled states, read from.list's and.menu's custom
properties. The chevron isIconProvider's newexpandicon, or the tree'sexpandIcon.
Patch Changes
-
98e8cb9: Fix
asChilddropping the component's own handling of the element it renders. A component now
treats its child as it treats the same element passed tocomponent, so
<Button asChild disabled><a href="/login">renders what<Button component="a" href="/login" disabled>renders.Button,Link,NavLink,CardLink,MenuItem,Chip,PaginationItem,Avatarand
ListItem, whendisabledwith a link child: the link getsaria-disabled="true"and
tabindex="-1"and its click is blocked, including the child's ownonClick. It used to get
an invaliddisabledattribute, or only a class, and still navigated.CloseButtonwith a link child keeps itsclose-buttonclasses and itsCloselabel.ListItemwith a link or<button>child getslist-action, andListrenders a<div>
around it instead of a<ul>.Stepperdoes the same for aStepperItem.ListandStepperwith a<ul>/<ol>child of their own keep rendering<li>items.Placeholderrenders its child as the image. It used to ignore the child and render the
generated graphic.- A plain tag as the child, such as
<div>, gets whatcomponent="div"gets:Buttonand
CloseButtonaddrole="button"and keyboard activation.
A component element with an
hrefortoprop, such as a router's<Link>, counts as a link.
Any other component element is still trusted with its own semantics, as withcomponent={...}. -
ee7c273: Fixes in
Calendar,RangeCalendar,DatePickerandDateRangePicker:- With
visibleMonthsabove 1, a day in the weeks of two visible months showed as a day of both:
selected, focusable and selectable twice, and a range drew its band over it in each grid. It is
now a day of its own month only, and greyed out in the other, as it is with one month. - A range's endpoint kept its highlight in the grid of the month next to its own, and the band
stopped square beside a day it can't hold (an unavailable or disabled one, another month's). The
endpoint is highlighted in its own month only, and the band is capped wherever it breaks. - Pressing a greyed-out day while selecting a range ended the selection at the last day hovered.
The press now does nothing, and the selection stays open. - Tab stopped on every day that can't be focused: the days of another month, and the ones outside
minValue/maxValue. It leaves the grid from the focused day. - A calendar no longer takes focus when it mounts under
StrictMode. - With
visibleMonthsabove 1, picking a month or year, or backing out of that view, in a block
other than the one holding the focused day dropped focus to the document body, out of a
picker's popover. The block's month or year button takes it. - The global previous/next buttons stayed hidden once
visibleMonthswas lowered while a removed
block was showing its month or year view. - The year view repeated an era's first year when paged back past it, in a calendar with eras
(ja-JP-u-ca-japanese). It now crosses into the era before. RangeCalendar'spresetsare disabled with the calendar; they used to select a range on a
disabledone. A preset now drops a selection begun in the grid, which stayed pending and was
finished by the next day pressed, and moves the calendar to a range that starts outside the
visible months.unavailableDatesnow marks a value with a time (granularity) invalid. Only date-only values
matched itsYYYY-MM-DDentries.labels.calendarnames the calendar button ofDatePickerandDateRangePicker. It was read
only withselectionMode="multiple".DatePickerwithselectionMode="multiple"shows aZonedDateTimeon its own day, not the day
its instant falls on in the viewer's time zone.
- With
-
4e4bd7b:
Modal,DrawerandAlertrendered withopenstay open. They used to close themselves right
after mounting (and after hydration, in a server-rendered page), firingonHidden, because their
state started closed.openis now the initial state when neithervisiblenordefaultVisible
is set: the dialog is open from the first paint, server HTML included, as a non-modal dialog, and
stays open until a close request. -
913b42f: Fix what server-rendered HTML shows before the page hydrates. Each component now renders on the
server what it settles to in the browser.Tabswith neitherselectedKeynordefaultSelectedKeyselects its first enabled tab and
renders that tab's panel on the server. That tab is the tab stop, so Tab reaches the list before
hydration.- A
ToastorNotificationshown on its first render is rendered withshowand hydrates
without replaying its enter transition;onShowstill fires once. One mounted later animates in
as before. Carouselrenders its indicators and marks its active slide on the server, so a
transition="fade"carousel is no longer blank until hydration, and its end controls start in
the right state. Slides getrole="group", which theiraria-labelrequires.- A
Menuopen on its first render shows its list once it has a position, instead of at the top
left of the page. A closedMenuorMenuSubmenulist no longer hasaria-hidden: chassis-css
hides it. CalendarandRangeCalendar, and the date pickers' calendars, mark today after hydration, in
the browser's time zone instead of the server's.- Fields no longer refer to ids that don't exist in the server's HTML:
TextInput,Textarea,
Checkbox,Switch,Radio,CheckboxGroup,RadioGroup,ChipInput,OtpInput,
DatePicker,DateRangePickerand the selection checkboxes ofTableandDataGrid. The
triggers of aPopoverorTooltipopen on first render getaria-controlsor
aria-describedbyonce the overlay exists. TableandDataGridno longer write an emptyaria-describedby, an emptyDataGridno longer
writes a negative height, and an emptyChipInputno longer writesaria-multiselectableon its
group.- A masked
OtpInputgives every boxautocomplete="one-time-code". Browsers ignoreoffon a
password field, so they offered saved passwords in each box.
-
45bff89:
TextInput,Textarea,NumberField,Checkbox,Radio,Switch,RadioGroupandTabList
render the attributes and event handlers their props accept. They are built on react-aria hooks,
which return only the props they know, sotitle,dir,lang,accessKey, mostaria-*
attributes,onClick,onMouseEnterand the other pointer handlers never reached the element,
tabIndexwas always0,requiredwas dropped, andNumberFieldignoredautoCompletefor
"off". A handler the hook runs itself, such asonFocusoronKeyDown, still runs once.
Radiokeeps its group'snameand its rovingtabIndex. ACheckboxorRadiogiven
autoComplete, which HTML doesn't allow on a checkbox or radio, now renders it; the docs'
toggle-button examples, which passedautoComplete="off", no longer do.stylegoes on the outermost element, asclassNamedoes: the.form-inputwrapper of a
TextInputwith an adorn, and the.form-checklabel of aCheckbox,RadioorSwitch.
TextInput,Checkbox,RadioandSwitchused to drop it, andSwitchwithtype="radio"
put it on the input. -
ca154a2: Fix hydration errors from portaled overlays.
ComboboxandAutocompletealways failed to hydrate,
as didFormFieldaround aComboboxand aPopoveropen on first render: their overlay was
portaled on the client's first render but not on the server. Every portal (Combobox,
Autocomplete,Popover,Tooltip,Menu'scontainer,MenuSubmenu, andToasterwith
placement) now renders nothing on the server and during hydration, and portals once hydration
has finished. AToasterwithplacementno longer renders inline on the server. -
379c3b9:
ListItemrendered as a link or button no longer writes itsactiveanddisabledclasses
twice, and a disabled button item no longer carriesaria-disablednext to its owndisabled
attribute.Link, which renders interactive items, already sets both. -
626f373: Remove the
react-transition-groupdependency.Collapse,TabPanel,Toast,Notification,
TooltipandPopoverapply the same chassis-css classes in the same order as before.- A transition now lasts as long as the element's own CSS transition, as it already did for
Modal,DrawerandMenu, instead of a duration fixed in the component. A theme that changes
a transition's duration is followed, and so isprefers-reduced-motion. - Fix a queued toast coming back after it was closed (#40). A
ToastorNotificationthat
unmounts before its exit transition has finished now callsonCloseas it unmounts. AToaster
remounted by a navigation, such as a Server Action that redirects, no longer shows the toast
again. - A newly selected
TabPanelstarts to fade in as soon as it is in the page. It used to wait
150 ms at full transparency first. Collapsekeeps astylepassed to it while it animates. Thestyleused to replace the size
the transition needs, so the transition didn't run.
- A transition now lasts as long as the element's own CSS transition, as it already did for
-
5a81190: Fix components that read their children when those children are written in a React Server
Component.Tabsrendered an empty tab list,ListandStepperrendered an<a>directly inside
<ul>/<ol>, andComboboxandAutocompletelisted no options. In a Server Component a
client component's element carries a lazy wrapper as its type, so the components didn't
recognize their own parts. This happened in production builds.asChildrendered the component's default element around the child and failed hydration, and
TooltipandPopoverthrew "Cannot read properties of undefined (reading 'ref')", when the
child held something still loading, such as a client component passed by reference (#37). This
happened undernext dev.- An icon element passed to
IconProvideror to a component's icon prop could throw the same way.
A component that reads a child now waits for it when it is still loading, as a lazy component
does.Tablestill can't be composed in a Server Component; useStaticTablethere. -
a15fcd4:
CalendarandRangeCalendar, and the date pickers' calendars, no longer call a day "Today" in its
label in server-rendered HTML. react-aria writes "Today, …" into a cell'saria-labelwith the
server's date and time zone, and hydration doesn't patch attributes, so a statically built page
named its build day as today until the cell re-rendered. Until hydration a cell's label is now
react-aria's for a day that isn't today, in the same locale ("Thursday, October 1, 2026 selected");
once hydrated it is react-aria's own, "Today" included, on the same day thedatepicker-date-today
class andaria-current="date"mark. -
9e4f450:
ButtonGroup verticalstacks its buttons. It renderedbutton-group vertical, a pair of classes
@chassis-ui/csshas no rule for, so the group stayed a row; it rendersbutton-group-vertical
now, the class of the framework, in place ofbutton-group.sizehas no effect on a vertical
group, as in the framework: size its buttons themselves.RadioGroupandCheckboxGroupwithorientation="horizontal"wrap their items onto further
lines when the container is too narrow for one. They overflowed it.