Changelog

Published versions of @radui/ui. Minor and patch sections follow SemVer. Source: CHANGELOG.md in the repository.

Release

v1.1.1

npm
Patch Changes
  • d0b3237Document Separator keyboard and ARIA accessibility references.

Release

v1.1.0

npm
Minor Changes
  • d955028: feat(badge): soft label style by default

    Badges get a new look:

    • Default variant is now soft (was solid): a translucent tint of the badge's color with vivid text. Pass variant="solid" to keep the previous default.
    • Small rounded corners (--rad-ui-control-radius-sm) instead of a pill, and the mono font at weight 600, for every variant.
    • Without color, the soft badge uses the neutral gray scale.

    Every color scale clears WCAG AA (4.5:1 or better) in both light and dark. A new theme variable, --rad-ui-badge-soft-text-weight, tunes the soft text mix per appearance.

  • dc6aaa7: feat(build): publish per-component Clarity style sources

    Each component's Clarity styles now ship in the package and can be imported from @radui/ui/styles/clarity/<Component>/<file>.clarity.scss. For example, @radui/ui/styles/clarity/Button/button.clarity.scss.

    • The folder structure matches the source, so relative @use imports between components still resolve when you compile a single file with Sass.
    • @radui/ui/themes/default.css is unchanged and remains the recommended way to load the full Clarity theme.
    • The docs site uses these files to show the exact styles that ship in each released version.
  • 0bcb1ef: feat(theme): default Theme appearance to dark

    <Theme> now renders data-rad-ui-theme="dark" when no appearance is passed. Previously it defaulted to 'system' and followed the OS color scheme.

    To keep the old behavior, pass it explicitly:

    <Theme appearance="system">...</Theme>

    appearance="light" and appearance="dark" are unchanged.

  • 944003e: feat(meter): add headless Meter primitive

  • 3aabdde: feat(label): add Label component

    @radui/ui/Label renders a native <label> that names a form control (htmlFor, or by wrapping it).

    • Matches Radix Label: double-clicking the label doesn't select its text, while controls nested inside it still get their own clicks.
    • Supports asChild, customRootClass and ref forwarding.
    • Clarity and baremetal styles included.
  • 8d5c556: feat: right-to-left support for menus, Select, Combobox, NavigationMenu, TabNav and ScrollArea

    • DropdownMenu, ContextMenu: new dir prop. In RTL, ArrowLeft/ArrowRight open and close submenus, submenus open on the left, and the portaled content (and submenus) carries dir. rtl is deprecated in favor of dir="rtl".
    • NavigationMenu, TabNav: new dir prop; arrow keys follow reading direction.
    • Select, Combobox: dir on the root now also applies to the portaled listbox.
    • ScrollArea: horizontal scroll math and scrollbar placement use the computed direction (logical CSS insets, RTL scroll range).
Patch Changes
  • 9ff88bf: fix(a11y): Command separators and RadioGroup arrow keys

    • Command: Command.Separator is now hidden from assistive technology (aria-hidden, no role="separator"). A separator isn't an allowed child of the listbox it renders inside, so axe reported a critical aria-required-children violation.
    • RadioGroup / RadioCards: all four arrow keys move between options, whatever the orientation, as the WAI-ARIA radio pattern specifies. Radix and Base UI do the same. orientation still sets aria-orientation.
  • 76087cc: standardize asChild support across remaining compound card, steps, avatar group, scroll area, and table parts

  • 0221f95: standardize overlay portal container and forceMount APIs across menu, combobox, and hover card primitives

  • 0af1268: fix: Drawer focus management and stable Toast manager functions

    • Drawer: focus now moves into the drawer when it opens, and Tab stays trapped inside. The focus manager used to engage as soon as data-state flipped to open, but the themes keep the popup visibility: hidden until the entrance transition starts. Initial focus found nothing focusable and silently failed, so keyboard and screen-reader users were left on the page behind the modal. It now waits until the popup is actually visible (capped at about 0.5s).
    • Toast: the functions from useToastManager() (add, close, update, promise, dismiss, dismissAll and the variant helpers) are stable for a given manager, as in Base UI. They used to be recreated on every render. An effect keyed on one of them, such as an unmount cleanup calling dismissAll, then re-ran on every render and dismissed each toast as soon as it was added.
  • 6ae9df7: fix(tooltip): keep the Clarity tooltip dark in dark mode

    The Clarity tooltip used --rad-ui-surface-inverse, which flips to near-white under data-rad-ui-theme="dark", so tooltips rendered as a light box on dark pages. Tooltip content and arrow now read new --rad-ui-tooltip-background, --rad-ui-tooltip-text, and --rad-ui-tooltip-border aliases: inverse in light mode (unchanged), and a raised dark surface with a soft border in dark mode. Override those aliases on a Theme container to customise tooltip colors.

  • 5a38eef: docs(guides): add a troubleshooting guide for SSR, portals, and focus

    New docs/app/docs/guides/troubleshooting page covering the integration failures that are otherwise spread across guides, organised as symptom / likely causes / what to try:

    • hydration mismatches on overlay and theme components
    • portal containers rendering in the wrong place or missing theme tokens
    • focus not restoring after a dialog, popover, or menu closes
    • focus traps that are too narrow or too wide
    • overlays flashing or never opening on first paint
    • scroll lock leaking after an overlay unmounts

    Registered in docsNavigationSections and cross-linked from the existing SSR & No-JS Fallback guide.

Release

v1.0.1

npm
Patch Changes
  • 0257be0Emit CommonJS component bundles and root index files so every package.json export target exists in the published package.

Release

v1.0.0

npm
Major Changes
  • 56ab619: Tailwind CSS v4 support. Tailwind v3 is no longer supported.

    The Tailwind preset is now a CSS file instead of a JavaScript config object. Import it after Tailwind itself:

    @import "tailwindcss";
    @import "@radui/ui/themes/tailwind-presets/default.css";

    Breaking changes:

    • The @radui/ui/themes/tailwind-presets/default.js export has been removed. Upgrade Tailwind to v4 before upgrading Rad UI.

    • The preset covers colours only, as before. Spacing, radius, shadow, blur and typography keep Tailwind's own defaults.

    • The colour ramp no longer contains <alpha-value>. Opacity modifiers keep working (bg-gray-500/90), so nothing needs replacing.

    • Tailwind v4 dropped its default border colour, so bare border now inherits currentColor instead of gray-200. To restore the old default, add this to your base layer:

      @layer base {
        *,
        ::after,
        ::before,
        ::backdrop,
        ::file-selector-button {
          border-color: oklch(from var(--rad-ui-color-gray-200) l c h);
        }
      }
    • var(--color-gray-500) no longer resolves. Read var(--rad-ui-color-gray-500) instead, which is what v3 emitted anyway.

    Applying v4's utility renames to your own markup: shadow-sm → shadow-xs, shadow → shadow-sm, blur-sm → blur-xs, blur → blur-sm, backdrop-blur-sm → backdrop-blur-xs, backdrop-blur → backdrop-blur-sm, outline-none → outline-hidden, bg-gradient-to-* → bg-linear-to-*, and bare ring → ring-3. Running npx @tailwindcss/upgrade handles most of this automatically.

Minor Changes
  • 3fec6d3: Add a LiveRegion primitive for accessible status announcements.

  • 02254e0: table resizable columns

  • 56ab619: Release TextField and add theme styles for Fieldset.

    • TextField is now published. Previously it shipped with styles and tests but was missing from the export list, so @radui/ui/TextField did not resolve.
    • Fieldset now renders with Rad UI styling in both themes instead of the browser default, and its invalid and disabled props have a visual effect.
  • 63d644a: Support React 19 in asChild components and enable Tailwind alpha modifiers on design tokens.

    React 19 asChild refs — components that read a ref off the child element (Primitive, PopoverPrimitiveArrow, TooltipTrigger, AccordionHeader) accessed element.ref directly. React 19 promoted ref to a regular prop and left element.ref as a deprecation getter, so every asChild render logged "Accessing element.ref was removed in React 19" and consumers on React 19 saw warnings from components they never opted into. These now read the ref through a shared getElementRef helper that branches on the React major version, because both access paths warn: React 18 warns on props.ref, React 19 warns on element.ref. Behaviour is unchanged on both versions.

    React 19 peer range — the react and react-dom peer dependencies widened from ^18.2.0 to ^18.2.0 || ^19.0.0. Without this, an application on React 19 could fail installation while this release claims to support it.

    React 19 ref teardown — React 19 lets a callback ref return a teardown function, which React then calls instead of passing null. composeRefs fanned the node out to every ref but discarded those return values, so a composed ref silently swallowed every teardown an inner ref had registered. It now retains them per ref and replays them on detach, falling back to the old null contract for refs that register no teardown. React 18 has no way to run a teardown, so its behaviour is untouched.

    Tailwind alpha modifiers — the generated Tailwind preset emitted var(--rad-ui-color-*) for every ramp step, so Tailwind's <alpha-value> placeholder could never be substituted and opacity modifiers such as bg-gray-50/90 silently produced no color. The preset now emits oklch(from var(--rad-ui-color-*) l c h / <alpha-value>), which enables the full /<opacity> syntax across every palette and step. This changes the CSS your build emits for preset-derived color utilities, and it relies on relative color syntax (Chrome 119+, Safari 16.4+, Firefox 128+). That is inside this project's stated support policy of the latest two stable versions of each evergreen browser, but it does raise the effective floor for apps pinning older browsers, so it is released as a minor rather than a patch.

    Token adjustment — --rad-ui-text-muted in the Clarity design system now resolves to --rad-ui-color-gray-950 instead of --rad-ui-color-gray-800, bringing muted text closer to the secondary text ramp for legibility.

Patch Changes
  • 68d9ea9: Expose stable Accordion anatomy data slots for root, item, header, trigger, content, and content inner parts.

  • 2fc2c28: Add a composable Breadcrumb component with accessible navigation semantics.

  • 1cb98d6: Add Button and Link keyboard interaction and ARIA reference docs.

  • 1899f88: Add Checkbox keyboard interaction and ARIA reference tables to the docs.

  • d8d348c: Document CheckboxCards keyboard interactions and ARIA references.

  • 0e2c3a8: fix(checkbox): expose protected anatomy and state data attributes

  • 55ee49a: Accessibility and Clarity cleanup across core controls: fix menu/navigation semantics and dismissal, form prop/state routing for Checkbox, Radio, TextArea, Fieldset, Text, and Slider, Avatar/Skeleton sizing, and contrast/alignment issues in the Clarity theme.

  • 1ea8953: Document CheckboxGroup keyboard interactions and ARIA references.

  • 5ff13c7: Expose stable data-slot anatomy markers on CheckboxGroup parts.

  • ae43686: Add an automated Clarity design-system audit gate and close the first tranche of findings it surfaced.

    The gate (npm run check:clarity, wired into CI) fails on raw colors, token fallbacks, hand-coded shadows, filter: drop-shadow, and literal duration, spacing, radius, typography, and sizing values. It carries a per-rule budget that acts as a ratchet: CI fails only when a rule goes above its recorded count, and that count drops as findings are fixed. Rules added later start at zero.

    All color, shadow, and motion findings are now zero. Popover's navy shadow and Toast's hand-picked status hexes were replaced with tokens, which fixes their dark-mode rendering; the Radio family shared one control shadow; AvatarGroup referenced an undefined --rad-ui-text. Two dense type sizes that had no token (0.8125rem and 0.9375rem, previously literals in 13 components) are now generated scale steps behind dense and comfortable aliases.

    No rendered value changes: each swap was verified against compiled CSS.

  • 10dbaf0: Document Collapsible keyboard interactions and ARIA references.

  • 3406f13: fix(collapsible): publish measured content dimensions when forceMounted

    With forceMount, CollapsiblePrimitive.Content is already present, so in the zero-duration branch both setHeight(undefined) and setIsPresent(true) bail out as no-ops and no re-render is scheduled. The measurement from that pass lives only in refs, so the measured size never reached the CSS variables and --radix-collapsible-content-height / --rad-collapsible-content-height were left at their initial 0.

    That matters most under prefers-reduced-motion, where the resolved transition duration is 0 — so the affected path is the default for those users:

    <CollapsiblePrimitive.Root defaultOpen>
      <CollapsiblePrimitive.Content forceMount>…</CollapsiblePrimitive.Content>
    </CollapsiblePrimitive.Root>

    Before, the content height variable read 0px; it now reads the measured height.

  • 1853344: Add Combobox large-list documentation with an incremental loading example.

  • b45059a: Document Command keyboard interactions and ARIA references.

  • 90f0db6: docs(contributing): add component docs templates for Accessibility and Features sections

    Adds two contributor guides alongside the existing component-docs-anatomy and component-docs-styling templates:

    • component-docs-accessibility — keyboard table format, ARIA/role and state attribute requirements, and a checklist that ties each section back to the keyboard interaction spec and screen reader testing guide.
    • component-docs-features — the short scannable Features bullet list, with rules for deriving bullets from the shipped public API.

    Both are also registered in docsNavigationSections, titled Component Docs: Accessibility and Component Docs: Features to match the existing Component Docs: Anatomy / Component Docs: Styling entries.

  • 4e3b3fe: Document CSS variable fallback and partial token override expectations for Rad UI styled layers.

  • 05c0ccb: Add defaultOpen to Dialog.Root and fix controlled/uncontrolled handling

    DialogPrimitive.Root now accepts defaultOpen for uncontrolled usage and switches from hand-rolled useState + useEffect syncing to the existing useControllableState hook.

    This also fixes controlled mode. Previously open was seeded into local state and re-synced by an effect, so a controlled dialog still opened when the trigger was clicked even though the parent held open={false} — the effect only re-ran when open itself changed. With useControllableState, a defined open is authoritative: the dialog reports the request through onOpenChange and waits for the parent to update.

    AlertDialog inherits the same fix. Its onOpenChange test asserted the old behaviour (clicking the trigger opened a controlled dialog) and now asserts correct controlled semantics: the request fires, the dialog stays closed until the parent rerenders with open={true}.

  • 55d0806: fix(dialog): merge consumer props through getItemProps on Action and Cancel

    DialogPrimitiveAction and DialogPrimitiveCancel spread consumer props after the props returned by getItemProps, so a consumer handler replaced the library's own handler instead of running alongside it.

    On Action, passing an onClick silently suppressed the close: the internal handleOpenChange(false) was overwritten, so the dialog stayed open.

    Both parts now pass consumer props into getItemProps and compose onClick explicitly, so the consumer handler runs first and the dialog still closes:

    {...getItemProps({
        ...props,
        onClick: (e) => {
            onClick?.(e);
            handleOpenChange(false);
        }
    })}

    DialogPrimitiveContextType also widens getItemProps, getReferenceProps and getFloatingProps to accept optional user props, and the default context value returns those props unchanged instead of {}.

  • ebcab1f: Expose Dialog trigger data-state, data-disabled, and aria-expanded attributes from the primitive.

  • 79e711d: Add Disclosure keyboard interaction and ARIA reference documentation.

  • 51a45ac: Expose stable Disclosure anatomy data slots and initialize defaultOpen.

  • 87604b7: Document Drawer keyboard interactions and ARIA references.

  • 7d338d9: docs(drawer): add the component documentation page and align the internal context type

  • 1ec9c6d: fix(drawer): resolve peekStyle temporal dead zone in DrawerContent

    DrawerContent referenced peekStyle inside the getFloatingProps call before the variable was declared further down the component body. The const declarations sat below an early return, so the reference landed in the temporal dead zone. The file failed to type-check, which broke four Drawer test suites at compile time.

    Hoisting the peekOffset/peekStyle pair above the getFloatingProps call fixes the ordering. getFloatingProps is also cast to its user-props signature, matching the convention already used by Dialog, Combobox and Menu.

  • 54b05e7: Add a Fieldset component with native legend semantics, grouped form-control slots, accessibility docs, and state data attributes.

  • f2c6bfb: Document HoverCard keyboard interactions and ARIA references.

  • 4095f30: Expose stable data-slot anatomy markers on HoverCard root, trigger, content, and arrow parts.

  • 285c5c8: Document Live Region keyboard behavior and ARIA references.

  • 0f04b58: docs(a11y): add ARIA references for select, combobox, and dropdown menu

  • 465e6d1: Document NumberField keyboard interactions and ARIA spinbutton references.

  • 66a89d5: Expose Popover anatomy data slots for root, anchor, trigger, content, close, and arrow parts.

  • db4c358: Collapsible primitives respect prefers-reduced-motion

    Adds a usePrefersReducedMotion hook and uses it to resolve the Collapsible height transition.

    transitionDuration was previously defaulted to 300 in CollapsiblePrimitive.Root, which meant the content type could not tell "the consumer asked for 300ms" apart from "nobody asked for anything". The default is removed and the value is resolved in CollapsiblePrimitiveContent:

    const resolvedTransitionDuration =
      transitionDuration !== undefined
        ? transitionDuration
        : prefersReducedMotion
        ? 0
        : DEFAULT_TRANSITION_DURATION;

    So an unset transitionDuration now collapses the animation entirely when prefers-reduced-motion: reduce is set, rather than still animating for 300ms. An explicit transitionDuration always wins, which is the escape hatch for anyone who needs to keep animating.

    The hook is SSR-safe: it returns false until mounted, then follows the media query, and supports both addEventListener and the legacy addListener APIs.

    Note that transitionDuration on CollapsiblePrimitiveRootProps is unchanged for consumers — it was already optional at the prop level; only the internal default is gone.

  • f83f617: Document Progress keyboard behavior and ARIA references.

  • 16ed885: Render indeterminate Progress without determinate ARIA value attributes.

  • 09da0e2: Keep Progress.Indicator out of the accessibility tree as a second progressbar while preserving its styling data attributes.

  • 669e5d8: Document Radio keyboard interaction and ARIA reference tables.

  • 06d4f89: Expose stable Radio state and anatomy data attributes.

  • 903a35d: Expose stable RadioGroup anatomy markers through data-slot attributes on root, label, item, and indicator parts.

  • e0a9b2d: Document Slider and RadioCards keyboard interactions and ARIA references.

  • e6dde24: Add ScrollArea keyboard interaction and ARIA reference tables to the docs.

  • 0ccabb4: fix(scrollarea): hide the scrollbar while a document overlay is open

    An overlay (Dialog, Menu, Popover, Combobox, Drawer) covers the page and locks body scroll, but a ScrollArea with type="always" still painted its scrollbar and thumb on top of it.

    Adds a document-level overlay registry and suppresses the scrollbar and thumb while any overlay is open:

    const isVisible =
      !overlaySuppressesScrollbar &&
      (type === "always" ||
        (type === "auto" && isOverflowing) ||
        (isOverflowing &&
          (type === "scroll" || type === "hover") &&
          scrollbarVisible));

    The registry is ref-counted and mirrors its state onto data-rad-ui-overlay-open on <html>, so overlays stack correctly (two open overlays decrement back to zero rather than clearing early). ScrollArea picks the state up via useDocumentOverlayOpenState, which also observes the attribute and body's inline style, so overlays from other libraries that only lock body scroll are covered too.

    resetDocumentOverlayOpenForTests is wired into the global afterEach in setupTests.ts so the registry cannot leak between suites.

  • ffab89f: Expose stable Select anatomy markers through data-slot attributes on root, trigger, content, group, item, item text, and item indicator parts.

  • 8f8574c: Add Select documentation for large option lists.

  • ed757fa: Improve Splitter handle accessibility with separator range attributes, Home/End keyboard resizing, and matching docs tables.

  • 6c18fcb: docs(a11y): add ARIA references for alert dialog, context menu, and menubar

  • 279d111: Document Switch keyboard interactions and ARIA pattern references.

  • bfd1085: Expose stable Switch anatomy data slots and keep the thumb visual-only for assistive technologies.

  • 5f1af85: Expose stable Tabs anatomy markers through data-slot attributes on root, list, trigger, and content parts.

  • 8284dc5: Added TextArea accessibility docs covering keyboard behavior and native multiline textbox semantics.

  • 8ca42a5: Expose TextField anatomy through stable data-slot attributes.

  • 88c11a3: docs(toast): add keyboard interaction and ARIA reference tables

  • ebe6ba7: Document Toggle and Toggle Group keyboard interactions and ARIA references.

  • 32d31e8: Expose Tooltip anatomy data slots for root, trigger, content, and arrow parts.

  • 91d18f6: Document Tree keyboard interactions and ARIA tree view references.

  • dc01059: docs(Tree): add large-data branch mounting guidance and correct item API docs.

Release

v0.6.0

npm
Minor Changes
  • fa1a1d5scroll area visual types
  • 1535c08new toast component
Patch Changes
  • 3a9ef46Add configurable loop focus-wrapping options for Tabs, Disclosure, Tree, and NavigationMenu, including NavigationMenu content panels.
  • b7d4406Restore Menubar horizontal keyboard navigation when focus is inside open menu content.
  • b7d4406Preserve inline AspectRatio styles while applying its ratio value.
  • b577317popover - improve radix api parity, modal focus behavior, arrow styling, and positioning stability