@zenoxai/ui
0.1.0
Minor Changes
-
e3ebca4: Data display holds its density and treats values the same way everywhere.
- New
EmptyValue(@zenoxai/ui/patterns/empty-value): a muted dash for a missing value, announced aslabel(“No value” by default). Use it instead of a blank cell, “N/A” or “-”. - Table:
containerClassNameonTableandstickyonTableHeader, for a long table that scrolls inside its own container with the header in view. A selected row usesbg-primary-soft(it was a 40% tint, hard to tell from hover); hover isbg-surface-muted/60; the caption is left-aligned. - SeverityBadge
softuses the shared soft fills and Badge’s 8px padding, so severity and status chips side by side use the same reds and ambers. - ConfirmDialog: the value to type shows as a monospace chip on a muted fill. Write
inputField.labelwithout the value (“Type the tenant name to confirm”). - SectionHeading and CardAction center the action on the title and description together.
- Chart: axis labels take the muted text token again (the selector missed Recharts 3), and the tooltip uses the Popover surface at body size.
- InfoBanner is one row: the icon sits on the first line and the banner is 36px with or without an icon.
- ValueActions keeps a table row at its normal height; AvatarGroup rings use the surface color
and overlap less, so initials are not cut; HelpTooltip’s pointer target is 26 or 28px;
DescriptionList keeps its label column at least 7.5rem wide; Item
smis 8px tighter thandefault; ListErrorState’s icon uses the danger tone; the ScrollArea thumb is visible.
To update: if an app styled its own sticky table header around Table’s scroll container, use
stickyinstead. - New
-
6a55cc8: Form controls share one size scale, one hover step, one disabled rule and one focus ring.
- New
sizeprop (sm28px,default32px,lg36px) onInput,InputGroup,ComboboxInput,NumberInputandNumberInputRoot;lgadded toSelectTriggerandNativeSelect. ReplaceclassName="h-7"on these controls withsize="sm".Inputno longer accepts the native numericsizeattribute; set the width with a class. - Breaking (0.x):
InputGroupButtonsizes are now the Button sizes of the same name, soxshas Button’stext-xstext and a 12px icon,icon-xsa 12px icon, andsmandicon-smare 28px instead of 32px, so they fit inside the group’s border. In ansmgroup, use thexssizes. - Icons follow the size name: 12px at
xs, 14px atsm, 16px atdefaultandlg. Buttonicon-smnow has a 14px icon, and the Select and Native Select chevrons are 14px atsm. NumberInputwith steppers is 32px tall, like Input (it was 34px), with Input’s padding, dark fill and focus ring; the stepper icons are 16px.- Hover is
surface-mutedin both themes on ghost and outline Buttons, Toggle and calendar days. The outline Button andButtonGroupTextuse the field border (border-input), and the outline Button shows the focus border in dark. - Disabled controls are dimmed to 50% with no fill change, and a group dims once. A Button
with
aria-busy="true"is not dimmed: disable it and setaria-busywhile an action runs. - Unchecked Checkbox and Radio borders and the off Switch track use
border-control(3:1); the Slider and Progress tracks useborder-strong. - Search inputs no longer show the browser’s own clear button: each browser drew its own. Build
a clear action with an
InputGroupButton, as the Input Group docs show. - Calendar: the selected day keeps its fill on hover in dark, today is marked by primary
semibold text instead of a fill, the days inside a range use
primary-soft, and the day buttons use the cell radius. - Combobox highlights items like Select and the menus (
primary-soft), opens 4px from the field, and its chips are 20px with a border. Select and Combobox popups use the motion tokens. - Select and Native Select use 16px text below
md, so iOS no longer zooms on focus; the Select trigger stays highlighted while open. - Slider thumbs show the focus ring on keyboard focus.
aria-invalidonInputOTPnow marks every slot; drop it from the slots.- Smaller fixes: Filter Chip
lguses the 12.5px body text,Labelhas the line height ofFieldLabel,ButtonGroupsetsdata-orientation="horizontal"by default, Textarea hides the resize grip where it grows with its content, and the fields set their text color.
- New
-
a0cfc6a: First release of
@zenoxai/uias a standalone, versioned package.-
58 primitives on Base UI 1.9, merged with the latest shadcn
base-novasources while keeping every Zenox customization; new:Drawer,Field,Logo(Zenox and Tellyu marks). -
12 patterns, several promoted from the Vydar web app:
PageHeader(now withiconandhint),StatTile,StatusBadge,SeverityBadge,CopyButtonandValueActions,DescriptionList,ConfirmDialogHostwith an imperativeconfirm(),ListEmptyState,ListErrorState,InfoBanner,SectionHeading,HelpTooltip. -
Token values unchanged except one: light
--text-mutedgoes from #647585 to #5c6c7c, which reached only 4.0 to 4.4:1 on--backgroundand--surface-mutedand now passes WCAG AA on every light surface. Added--brand-mark(text-brand-mark): the brand blue in light mode, white in dark mode, the default color of the logo components. Added--severity-*-soft-foreground(text-sev-<level>-soft-fg) so the soft severity badge reaches WCAG AA. Fixed:.force-lightnow uses the same--inputborder as light mode, and alias tokens (--card,--toast-*, …) resolve per theme scope instead of freezing to light values below<html>. -
Fonts move to the variable
@fontsource-variablepackages (one file per family). -
Toasterfollows the.darkclass throughuseColorScheme()and no longer needsnext-themes. -
Chart moves from
patterns/charttocomponents/chartand is imported from that subpath only: the root entry does not re-export it, so apps withoutrechartscan import from the root. -
Accessibility fixes in the promoted patterns: a clickable
StatTileno longer nests the hint button inside arole="button"card; thePageHeaderhint sits beside the<h1>;CopyButtonannounces the copy and reports a missing Clipboard API;ConfirmDialogtype-to-confirm is a single-line field that confirms on Enter and shows the expected value;InfoBanneris arole="note"instead of an alert. -
Fixes in the primitives: Alert contrast; Badge defaults to the neutral tone; Checkbox and RadioGroup disabled styles and the indeterminate dash; Pagination links are links, not buttons; named Combobox buttons; Sidebar
aria-currentand a shortcut that leaves text fields alone; Carousel keys for vertical and RTL; one Slider thumb per value andthumbLabels; ToggleGrouporientation; CommandDialog title placement; Toasterstylemerge; NumberInput aligned with Input; one menu highlight style. The table header sits on a tinted band (bg-surface-muted) withtext-text-secondarylabels, so it reads apart from the rows. The full list is indocs/audits/2026-10-23-web-app-ui-audit.md.
Migrating from the workspace copy in zenox-web-app: see
docs/migration/from-zenox-web-app.md. -
-
855f68d: One look for selected and pressed items, toasts in the colors of their type, and dark-theme tokens that keep states visible.
- Selection colors: a pressed Toggle and ToggleGroup item, the active FilterChip, the current
sidebar item and the highlighted item of every menu use
bg-primary-softwithtext-primary-soft-foreground.text-primaryon that fill was 4.0:1 in dark. - ToggleGroup: the segmented variant is as tall as a Button of the same size (28, 32 or 36px,
track included), with concentric radii, and keeps one item pressed when it is not
multiple. Joined outline items overlap their borders, so a pressed item shows its whole primary border. - Toaster:
toast.success(),info(),warning()anderror()take the colors of the Alert of the same tone by default (richColorsnow defaults totrue; passrichColors={false}to keep every toast neutral). Toast text uses the type scale and the text tokens. New--toast-warning-*tokens. - Theme, dark:
--surface-mutedis#26262f(hover, header bands, skeletons and tracks were 1.08:1 against the surface),--text-mutedis#8b95a1,--inputis--border-strongand--success-softis#052e16. Light:--chart-5is#4796cb(the brand accent was 1.4:1 on white). - New tokens:
--border-control(border-border-control), the 3:1 outline of a checkbox or a radio, and--severity-{critical,high,medium,low,info}-soft(bg-sev-*-soft).
To update: if you passed
richColorsto everytoast()call, you can drop it. - Selection colors: a pressed Toggle and ToggleGroup item, the active FilterChip, the current
sidebar item and the highlighted item of every menu use
-
709bf6b: StatTile keeps its figure neutral and gains a standard delta, units, exact values and a no-data state.
- The figure is semibold (it was bold) and never colored.
tone="warning"andtone="danger"now color themetaline, the reason the figure needs attention, and add the tone’s icon. Writemetaas that reason (“Above the target of 10”); a toned tile withoutmetashows the icon beside the label. - New
deltaprop andStatDeltacomponent: the change against a previous period on a soft chip with an arrow.trendsets the arrow,sentiment(positive,negative,neutral) sets the color,labelis what screen readers announce. - New
unitprop: the unit sits after the figure, smaller and in secondary text, and is read with it (“Patch coverage: 92%”). - New
exactValueprop: the exact figure behind an abbreviation, on hover and for screen readers. valueacceptsnull: the tile shows an empty value instead of a figure.- A clickable tile’s hover is a neutral border and fill instead of a primary-tinted border, and its keyboard focus ring is drawn on the card (it was clipped by the card’s overflow).
- A loading tile keeps the height of a loaded one: the meta line gets its own skeleton.
To update: replace hand-built deltas in
trailingwithdelta, choosingsentimentper metric. Passnullinstead of0when the figure is missing. Check themetaof every toned tile reads as the reason for the tone. - The figure is semibold (it was bold) and never colored.
-
018db60: The type scale moves to rem, raises its floor to 11px and gains a compact title step (ADR 0006).
- Sizes and line heights are in
rem. At the browser’s default 16px nothing moves; when a user raises the browser’s font size, text now grows together with spacing and control heights. text-xsis 11px on a 16px line (it was 10px on 14px). Badges, keyboard hints, menu labels, shortcuts, chart text andxsbuttons grow by 1px. Badge keeps its 20px height.- New
text-md(14px / 20px), the compact title step.cn()knows it, so it is not dropped when merged with a text color. - Title weights follow the role: page and section headings stay semibold, container titles
(Card, Dialog, Alert Dialog, Sheet, Drawer, Empty) stay medium, and compact titles are
semibold.
PopoverTitleand the title of asize="sm"Card move from 12.5px medium to 14px semibold.CardTitledropsleading-snug, so a default card title sits on a 24px line. text-dense-xsis now a deprecated alias oftext-xs.- Select triggers and sidebar menu buttons lose vertical padding inside their fixed heights, so the text line always fits the box.
To update: replace any
text-xsused for a sentence, help text or a code block withtext-sm; the guidelines no longer allow it. Replacetext-dense-xswithtext-xs. Afont-semiboldoverride onCardTitleorDialogTitlegoes against the title levels; remove it. - Sizes and line heights are in
Patch Changes
-
51f3289: The documentation moves to https://ui.zenox.services: the links in
ai/USAGE.mdand in the generated component registry (ai/components.json,ai/components.md) point there. The registry also followsDOCS_SITE_URLwhen it is set, like the docs build. -
d7594e0: Navigation, tabs and disclosure components follow the selection, focus and motion rules of the rest of the system.
- Tabs: the default variant is the segmented ToggleGroup control. The list is a bordered
bg-surfacetrack with a 2px inset, the triggers fill it (26px in a 32px track, 3px above and below), and the active tab takesbg-primary-soft,text-primary-soft-foregroundand a primary inset ring instead of a raised pill with a shadow. Hover isbg-surface-muted, and inactive text istext-text-secondaryin both themes. The line variant keeps its primary text and underline, and now scrolls sideways when the tabs do not fit; its bottom rule is an inset shadow instead ofborder-b, so the underline is no longer clipped. - Sidebar: hover and press use the neutral
bg-surface-muted; the selection tint marks the current page only, and keeps it on hover. Focus uses the system 3px ring.size="sm"menu buttons and both sizes of SidebarMenuSubButton use the 12.5px body text (heights unchanged); sub-button icons follow the text color. SidebarTrigger and SidebarRail are named “Toggle sidebar”. - Pagination: the current page takes the selection colors with a primary border instead of the outline button.
- Breadcrumb links show the system focus ring; the ellipsis is one line tall with a 14px icon, so the trail keeps its height.
- AccordionTrigger extends 8px past its item on each side, with matching padding, so the focus ring clears the text while the text stays aligned with the panel.
- CollapsibleContent animates its height with the AccordionContent keyframes instead of snapping.
- ResizableHandle: the line tints primary on hover and turns solid primary while dragged, the grip
uses
border-control(3:1 on the surface), the focus ring is the system 3px ring, and the pointer strip is 8px wide. - Carousel: below
md, CarouselPrevious and CarouselNext sit 8px inside the edges instead of off screen. Frommdup they stay 48px outside. - Skeleton uses
border-strongin dark, wheresurface-mutedfaded into the surface at the low point of the pulse. - AlertAction is centered on the first line of text at any button height. AlertDescription and
EmptyDescription use
text-text-secondary; EmptyDescription drops its relaxed line height and EmptyTitle its negative tracking.
To update: tests that find the sidebar trigger by the name “Toggle Sidebar” must use “Toggle sidebar”. An Accordion placed flush against the edge of a scrolling or clipping container with less than 8px of padding needs that padding, or its triggers overflow by 8px. A Carousel whose buttons you positioned with your own
left-*orright-*classes keeps them frommdup; belowmdaddmax-md:classes if you want a different placement. - Tabs: the default variant is the segmented ToggleGroup control. The list is a bordered
-
e0713e5: Overlays and menus now share one look, one motion and one row geometry.
- Dialog, AlertDialog, Sheet and Drawer: a 1px ring and
shadow-lg(Sheet and Drawer drop their inner-edge border), a 4px header gap, a 24px title line (Dialog losesleading-none) andtext-text-secondarydescriptions. AlertDialogdefaultis 400px wide fromsm, like asmDialog. - Dialog and AlertDialog stop at the viewport height less 1rem on each side and scroll inside, so the footer stays reachable on short screens.
- The Dialog and Sheet close button sits at the same offset (14px from the top, 12px from the right), centered on the first title line, and the header reserves room for it: long titles wrap before the X instead of under it.
- Sheet enters in 200ms and exits in 120ms with the theme easings, and its backdrop uses the
Dialog one. HoverCard, ContextMenu, Menubar and the NavigationMenu popup use the same
fade-and-scale transition as Popover and DropdownMenu instead of keyframe animations.
Submenus and the NavigationMenu popup use
shadow-mdlike every floating panel. - Menu rows line up: DropdownMenuItem moves from 8px to 6px side padding, like its checkbox,
radio and sub-trigger items. Menubar checkbox and radio items put the check on the right, as in
DropdownMenu and ContextMenu, and MenubarLabel uses the same caption style. Every menu popup is
at least 144px wide. All item types highlight on
data-highlighted. - Command: the highlighted item uses the selection colors (
bg-primary-soft,text-primary-soft-foreground, icons and shortcut included) instead of a near-invisiblebg-muted. Rows are 26px with a 4.8px radius and 6px padding, like menu rows, in a popover and in CommandDialog alike; group headings use the menu label inset. The Command root isrounded-lgand can be overridden withclassName. - MenubarTrigger shows the focus ring. NavigationMenu triggers and links are 32px high with a
16px chevron; the
activelink takes the selection colors and keeps them on hover; an open trigger uses the full hover fill. - HoverCard is centered on its trigger (
alignOffsetdefaults to 0). - Drawer: the header aligns left from
md(it stayed centered on wide screens), and a footer right after the header keeps a 16px gap without apt-4patch. - CommandDialog’s default
titleanddescriptionare now “Command palette” and “Search for a command to run”. If you relied on the old defaults, for example in a test that queries the dialog by name, pass them explicitly.
To update: remove any
className="pt-4"added to a DrawerFooter that follows a DrawerHeader, and anyinsetadded to Menubar labels or items only to line them up with checkbox items. - Dialog, AlertDialog, Sheet and Drawer: a 1px ring and
Release notes are generated by Changesets from the
files in .changeset/. Do not edit this file by hand.