@astryxdesign/core
Breaking Changes
Text,Heading,Link, andTimestamprename thecolor="active"value tocolor="accent", now mapping to the dedicated--color-text-accenttoken (legible accent text ink) instead of--color-accent. Runastryx upgradeto migrate call sites automatically. (#2863)
New Features
- Button: add
isInterruptibleto keep the button clickable while aclickActionis pending — the spinner andaria-busystill show, but the button is not disabled or deduped, so a re-click interrupts the in-flight action. ToggleButton's async toggle now runs through this path, staying interruptible. - Add a prebuilt UMD bundle (
dist/astryx.umd.js, globalAstryx) plusunpkg/jsdelivrfields, so the library works directly from a CDN via a<script>tag with no bundler. React/ReactDOM stay as peer globals; the StyleX runtime is bundled in. - Add
useTableStickyColumns— pin a contiguous run ofTablecolumns to
the start and/or end edge with cumulative offsets and scroll-aware drop shadows.
Configure with{ startKeys, endKeys }; an empty config is a valid no-op.
Fixes
- AvatarGroupOverflow now forwards rest props (data-, aria-, event handlers, id, role, tabIndex) to the rendered element, matching the behavior of Avatar and AvatarGroup.
- Fix HoverCard SSR hydration mismatch when used inside an SSR Client Component (#3107). The floating layer now renders inline instead of portaling to
document.body, so server and client markup match. No API change. - Kbd: use the
--color-border-emphasizedtoken for its bottom border instead of--color-border(#2850) - useLayer now treats
anchor-nameas a comma-separated list, so multiple layers can anchor to the same element (e.g. two TopNavMegaMenus in one nav) without clobbering each other's anchor. Previously the second menu lost its anchor and rendered over the nav. - Fix mobile nav drawer not re-opening after it is closed (#3091)
The AppShell mobile drawer mountsMobileNavinside an<Activity>that
switches tomode="hidden"when the drawer closes. On close, React runs the
drawer effect's cleanup (with a staleisOpen) instead of re-running the
effect withisOpen=false, so the deferreddialog.close()never fired and
the native<dialog>was leftopenin the hidden subtree. The next open then
skippedshowModal()(the dialog was already open), so the drawer could be
opened and closed once but never re-opened. The effect cleanup now closes the
dialog if it is still open, keeping the native dialog state in sync so a
subsequent open cleanly callsshowModal()again. - Core components (
Banner,EmptyState,Markdown) no longer render a<p>by default — they render<div>(appearance unchanged). This avoids hydration mismatches when block content lands in a<p>.Markdownparagraphs userole="paragraph"; passcomponents={{paragraph: 'p'}}to opt back into<p>. Pagination'schangeActionis now interruptible — page changes run in a transition with optimistic page state, so rapid prev/next clicks advance through pages instead of being dropped.Button'sclickActionkeeps its single-fire guard.- make the
Sliderdefault track color visible on muted backgrounds
The background track painted with--color-background-muted— the same token
used for muted surface fills — so the track disappeared on muted backgrounds.
The track now uses the dedicated--color-trackchannel token, which is
designed to stay legible against body/muted surfaces. - Polish
useTableStickyColumnspinned-cell backgrounds so they match the
rest of the row: - Table: the header row no longer picks up the
hasHoverrow highlight — hover (and striped) styling now applies to body rows only. Adds an internalisHeaderRowflag on the row component so the header row in<thead>opts out (#2734) Timestampnow renders the current time (and small clock skew up to ~30s in the future) as "now" instead of "in a few seconds" (#3099).- ToggleButton onPressedChange receives the click event for preventDefault opt-out
onPressedChangenow receives the originating click event as a second
argument. Callingevent.preventDefault()skipspressedChangeAction, so a
consumer can handle the toggle entirely inonPressedChangewithout firing the
action — matching howSwitch'sonChangeandButton'sonClickalready
gate their action props. Existing(isPressed) => voidhandlers keep working;
the event is an added trailing argument. - Tokenizer/PowerSearch: align end content (clear button, resultCount) with the field's inline padding instead of hugging the border (~3px). It now uses spacing-2 (8px) to match the text/start-icon inset (#2849)
- Tooltip and HoverCard: add ARIA roles to the floating layers —
role="tooltip"on Tooltip (completing the ARIA tooltip pattern; the trigger already links viaaria-describedby) androle="dialog"on HoverCard. Plumbed via a new optionalroleon the layer render props. (#3240; Popover already exposesrole="dialog".)
Documentation
- Document Banner's
defaultIsExpandedprop, which controls whether the collapsible content area starts expanded but was missing from the docsite properties tab - Rename the ClickableCard and SelectableCard examples to follow the "Component — Variant" title convention (
Clickable Card — Nested Button,Selectable Card — Multi-select), and add playground defaults to both card docs so their docsite previews show realistic card content (#2877) - Declare playground scaffolds for the Chat sub-components so they preview at a realistic width (ChatComposer and ChatComposerDrawer wrap in a sized container, and the drawer seeds default content), and drop the redundant visible value label from the ChatComposerDrawer "With Progress" example while keeping the accessible label (#2877)
- Document two public props missing from the docsite properties tab: List's
start(ordered-list counter start) and CheckboxInput'sisReadOnly - Restore the Icon and Skeleton properties-tab previews on the docsite. Icon now seeds a default
icon(it was a required, non-generatable prop), and Skeleton renders with concrete preview dimensions instead of collapsing at100%(#2848, #2875) - Document Heading's
justifyprop, which was supported by the component but missing from the docsite properties tab (#2847) - OverflowList: seed example items via playground defaults so the docsite properties-tab preview renders a real list instead of an empty container (#2872)
- Document Section's
paddingBlockprop (block-axis padding override), which was supported by the component but missing from the docsite properties tab - Give the
Skeletonproperties-tab example explicit dimensions so it is visible
TheSkeletondoc had noplaygroundconfig, so the interactive
properties-tab preview fell back to the prop defaults ofwidth: '100%'/
height: '100%'. With no sized parent, the skeleton collapsed to a zero-size
(invisible) element. The doc now sets aplayground.defaultsof
width: 320/height: 80so the shimmer placeholder renders visibly. - Update stale
facebookexperimental/xdsdoc/JSDoc links to the currentfacebook/astryxnamespace in source comments (theme/syntax@seereferences). The old org 301-redirects, so these weren't broken — just stale — and this matches the canonical org used elsewhere - Document Table's
verticalAlignandtextOverflowprops, which were supported by the component but missing from the docsite properties tab - Document TabList's
layoutprop ('hug' | 'fill') for tab sizing, which was supported by the component but missing from the docsite properties tab - Document Text's
justifyprop, which was supported by the component but missing from the docsite properties tab (same omission previously fixed for Heading) (#2847-adjacent) - Restore the Timestamp properties-tab preview on the docsite.
valueis a required prop with no semantic default, so the preview rendered "Invalid time value"; it now seeds a valid ISO 8601 date (#2877) - Document ToggleButton's
isIconOnlyprop, which was a supported public prop but missing from the docsite properties tab - Make the Toolbar "Table Filter" example use real Selector controls for its Status and Priority filters instead of buttons styled to look like dropdowns, and add meaningful playground defaults plus richer slot options (buttons, icon buttons, tabs, segmented controls, selectors) to the Toolbar docs (#2877).
Other Changes
- Pinned cells paint an opaque base via the overridable
--table-sticky-backgroundvariable (defaults to--color-background-card),
fixing a grey mismatch in themes/modes wheresurface !== card(e.g. neutral
dark). Consumers on a different backdrop override the variable. - The row's overlay (striping and/or hover) is replayed on the pinned cell via
a background-image gradient.TableRowpublishes its current overlay color as
the inheritable--table-row-overlayvariable, so pinned columns mirror the
row exactly — striped when the table is striped, hover when enabled, nothing
otherwise (no phantom stripes) — transitioning in lockstep with the row. background-clip: padding-boxkeeps the row divider visible on pinned cells.- New
transformScrollWrapperhook (+ScrollWrapperRenderProps) lets plugins attach aref
to the horizontal scroll container and inject before/after chrome. transformHeaderCell/transformBodyCellnow receivecolumnIndexand the
full orderedcolumnslist (also surfaced on the render props), enabling
position-aware plugins such as sticky columns. Existing plugins are unaffected
— the new args and methods are additive and optional.
@astryxdesign/cli
Breaking Changes
Text,Heading,Link, andTimestamprename thecolor="active"value tocolor="accent", now mapping to the dedicated--color-text-accenttoken (legible accent text ink) instead of--color-accent. Runastryx upgradeto migrate call sites automatically. (#2863)
New Features
- Let
astryx.config.mjsintegrations contribute package docs, gap-report hooks, template fetching hooks, upgrade codemods, and post-codemod hooks. - Add
astryx theme add <slug> [path](andastryx theme list) to scaffold a theme's source into your project as editable files you own, with theme sources bundled into the CLI
Fixes
- align
astryx inittheme instructions with the runtime built-theme recommendation (#3080)
astryx initnow points users at the pre-built theme path (@astryxdesign/theme-neutral/built+theme.css) and the base CSS imports, matching the runtime<Theme>console guidance, instead of the slower runtime style-injection import that left apps unstyled. astryx theme buildnow derives every output file (.css/.js/.d.ts) from the theme name so they share one naming scheme, shows import paths as bare./<name>specifiers (instead of a cwd-rooted./src/...path that was wrong when your file already lives under src/), and no longer warns about thevariantprop oncard
Documentation
- Rename the ClickableCard and SelectableCard examples to follow the "Component — Variant" title convention (
Clickable Card — Nested Button,Selectable Card — Multi-select), and add playground defaults to both card docs so their docsite previews show realistic card content (#2877) - Declare playground scaffolds for the Chat sub-components so they preview at a realistic width (ChatComposer and ChatComposerDrawer wrap in a sized container, and the drawer seeds default content), and drop the redundant visible value label from the ChatComposerDrawer "With Progress" example while keeping the accessible label (#2877)
- Rename the DateInput "Date Range" example to "Min/Max Constraints" — it demos a single input constrained to a min/max window, not a date-range picker (#2692)
- Wire local state into more showcase examples that were frozen (static value + no-op onChange): TextInput, TextArea, NumberInput, SegmentedControl, RadioList, Tab, TabList, and TabMenu. Follows the same fix as the Slider/Selector/MultiSelector showcases so the docsite previews are actually interactive
- Wire local state into the Typeahead, Tokenizer, and FileInput showcase examples (static value + no-op onChange → frozen previews). Completes the interactive-showcase fixes started for Slider/Selector/MultiSelector (#3187-#3189) and the input/tab batch
- Wire local state into the Slider, Selector, and MultiSelector showcase examples so they are interactive — they were controlled components with a static value and a no-op/missing onChange, so the docsite previews appeared frozen (#3187, #3188, #3189)
- Add a LinkProvider example block showing how to swap in a framework router link (e.g. Next.js Link) for client-side routing (#2733)
- Add a showcase block for Outline so its docs page has a hero preview, alongside the existing example blocks (#2871)
- Remove the "MoreMenu — In Toolbar" example block — it rendered incorrectly and was redundant with the other MoreMenu examples (#2870)
- Add rendered example blocks for the two column-axis Table plugin hooks,
shown on their own subcomponent pages: - Move the "ToggleButton — Group" example to the ToggleButtonGroup page, where it belongs (it demonstrates grouped toggle behavior) (#2842)
- Make the Toolbar "Table Filter" example use real Selector controls for its Status and Priority filters instead of buttons styled to look like dropdowns, and add meaningful playground defaults plus richer slot options (buttons, icon buttons, tabs, segmented controls, selectors) to the Toolbar docs (#2877).
Other Changes
useTableStickyColumns — Pinned Columns(on /components/useTableStickyColumns)useTableColumnResize — Draggable Columns(on /components/useTableColumnResize)
@astryxdesign/build
Fixes
- ship TypeScript declarations for the
@astryxdesign/build/viteexport
Contributors
@benjipeng @cixzhang @durvesh1992 @ejhammond @ernesttien @humbertovirtudes @rubyycheung
Full Changelog: v0.1.1...v0.1.2