Changelog

The notable changes to zits/ui and the Navius brain. Authored in markdown, rendered with Markdig.

August 2026: Dithered charts, and Drawer gets its clicks back

Published August 8 as Zits.Ui 0.3.0-preview.7, navius 0.3.0-preview.7, and Navius.Primitives 0.3.0-preview.6.

Charts get a pattern language. Area, line, bar, pie, donut, and radar series each pick a fill treatment — solid, Bayer gradient, dotted, or hatched — through ChartSeries.FillVariant, so a chart stays readable in monochrome, in print, and for readers who can't separate the categorical hues. Alongside it: opt-in Bloom (with a hover-only mode), sparkle accents on each series' peak, a reveal animation with a replay token, and series selection that dims everything else. All of the motion is off by default and every piece of it stops under prefers-reduced-motion.

Selection is operated from the legend. The plotted shapes take a click as a pointer shortcut, but they are not controls. Making each one a focusable button turned a six-category bar chart into twelve tab stops that all did the same thing, and role="img" on the pie container cannot legally host focusable children. A Selectable chart instead turns its legend into a row of named aria-pressed toggle buttons — one stop per series, correctly named, and the same surface for pointer, keyboard, and screen reader. The chart container also stopped cascading itself as a fixed value, which had left the legend and the plot showing different selections.

Every control inside a Drawer was dead. In the brain, the sheet-swipe engine took pointer capture on pointerdown, which retargets the compatibility mouse events — and click with them — to the panel. A press on a button inside the drawer dispatched its click on the sheet instead, so buttons, links, and fields inside it never fired, the built-in close included, leaving Escape, an outside press, or a drag as the only ways out. The carousel viewport had the identical defect for controls inside a slide. Both engines now claim the pointer only once the press has travelled past a threshold: a tap keeps its click, a drag still works from anywhere. Two smaller drawer defects went with it — a press used to leave an inline transition: none behind, permanently disabling the open/close animation, and a dismissed sheet leaked its drag transform into the next open.

July 2026: Package and motion audit

Published July 20 as Zits.Ui 0.3.0-preview.6 and navius 0.3.0-preview.6.

A solo clone builds. Zits.Ui referenced the sibling navius checkout unconditionally, so a clone without it did not restore. The dependency is now a switch: the pinned, published Navius.Primitives package by default (and on every publish, so the packed dependency is always a version that exists on nuget.org), auto-switching back to the local project reference when a side-by-side navius checkout is present.

Reduced motion covers more than the shimmer. Under prefers-reduced-motion, the skeleton pulse, the accordion height animation, and the scroll-driven edge fades now stop too, the fades falling back to their static mask. The spinner keeps rotating on purpose: it is the only loading affordance.

July 2026: Theme persistence across enhanced navigation

Published July 16 as Zits.Ui 0.3.0-preview.5 and navius 0.3.0-preview.6.

The theme no longer reverts on navigation. On a Blazor SSR site with enhanced navigation, every internal navigation patches the live DOM to match the freshly server-rendered document, stripping the client-applied .dark class and data-zits-* attributes from <html> — so a persisted theme selection restored pre-paint visually reverted on the first nav. zits-theme-init.js now restores the selection pre-paint and after every Blazor enhancedload event, staying a classic, dependency-free script that never throws on non-Blazor pages. Sites pick the fixed script up through the Zits.Ui static asset.

July 2026: Warning semantic role

Published July 12 as Zits.Ui 0.3.0-preview.4 and navius 0.3.0-preview.5.

Warning is an ecosystem semantic role. New --warning / --warning-foreground tokens for the light and dark themes, Tailwind semantic color utilities, system-color mappings in forced-colors mode, and Variant="warning" on ZitsAlert — coordinated with the Navius WPF port's Warning tokens so the role means the same thing across web and native. Warning stays conveyed through content and iconography rather than hue alone in forced-colors mode.

The Zits.Ui cut is also the first to package the helm fixes from the July 11 audit below.

July 2026: Controlled-state and vendoring audit

Published July 11 as Navius.Primitives 0.3.0-preview.4 and navius 0.3.0-preview.4; the helm component fixes first shipped in Zits.Ui 0.3.0-preview.4 (July 12).

Controlled-ness is decided by parameter presence, not HasDelegate. ~22 brain component roots decided controlled vs. uncontrolled from EventCallback.HasDelegate, so an uncontrolled component with a Default* seed plus an observer-only change callback froze at its default (NaviusDialog DefaultOpen="true" with an OpenChanged observer stayed shut). Every root now tracks whether its state parameter was explicitly supplied in SetParametersAsync and drives controlled-ness off that flag, and change callbacks fire as pure observers in the uncontrolled path. Public API unchanged, one regression test per family shape.

Conditional state forwarding in the helm. Twenty overlay, toggle, menu-item, and menu-radio wrappers forwarded their state parameter to the brain unconditionally, which under presence-based detection pinned the primitive into controlled mode at its default value. They now track supply in SetParametersAsync and forward state only when the consumer set it — the idiom the form wrappers already used.

Select keeps its label after the popup closes. The selected option's display label was resolved from the live item registry, which dropped the entry when the options unmounted on popup close, leaving the closed trigger showing the raw value key. The value-to-label map is now a persistent cache, retained on unmount.

Vendored wrappers compile clean. navius add output raised RZ10012 and rendered Navius tags as literal HTML, because wrappers resolved primitive tags through the library's own _Imports.razor, which vendored output doesn't carry. All 67 Navius-consuming components now carry local @using directives, and the vendor gate builds with -warnaserror:RZ10012.

DatePicker gets real grid keyboarding. ZitsDatePicker exposed role="grid" with ~30 tab stops and no arrow-key handling. It now composes ZitsCalendar (single mode) inside the popover — the shadcn Popover + Calendar shape — inheriting the full ARIA grid pattern: one roving tab stop, arrows by day and week, Home/End, PageUp/PageDown by month.

Theme reset leaves no dark residue. clearTheme removed the stored selection but deliberately left .dark on <html>, so the document stayed dark while state reported System until the next full load; invalid stored dimension values normalized in C# were never pushed back to the DOM. Both fixed.

July 2026: Initial release

The initial release is the full public cut of zits/ui: the styled helm, the Navius brain it depends on, the registry/CLI distribution path, the docs site, chat components, motion opt-ins, the parity push, and the runtime theme engine.

Component catalog

The complete styled set. zits/ui ships the full styled catalog as copy-paste source you own: every accessible primitive-backed component (Checkbox, Radio Group, Select, the menus, Tooltip, Popover, Slider, Toast, and more), the common layout and display pieces (Alert, Table, Pagination, Breadcrumb, Skeleton), and the heavier surfaces (Calendar, Carousel, Command, Data Table, Date Picker, Resizable, Sidebar, Drawer).

The Navius brain. Behind every interactive component is a headless, accessible primitive engine spanning ARIA, keyboard, focus, and a data-* state contract, driven from C# over a small dependency-free JavaScript engine for focus trap, anchored positioning, roving focus, dismissable layers, teleport, and more.

The styled helm. Tailwind components and an OKLCH token theme sit on top of the brain. The helm keeps familiar part names, but the underlying behavior stays in Navius.

Docs and distribution

This docs site. Built with the components it documents: every live preview is a real Blazor component running in WebAssembly. The site uses the Tailwind v4 standalone CLI, a command palette, a Blocks gallery, and a Markdig content pipeline.

Registry and CLI. The navius CLI and JSON registry distribute both styled helm source and the required brain primitives. The registry includes the full component set, cn, core primitives, chat, button, and the theme engine.

Chat and assistant UI

Chat set. A conversation kit for assistant and messaging UIs: Message, Message Scroller, Bubble, Attachment, and Marker, alongside the Scroll Fade and Shimmer helpers. The Message Scroller anchors turns near the top, follows the live edge until the reader scrolls away, preserves position when older history is prepended, and jumps to a message on demand.

Input, structure, and charts

Input families. Fourteen styled surfaces over Navius primitives, each with a real interactive preview: Date Input, Time Input, Time Picker, Date Range Picker, Color Picker, File Upload, Rating, Masked Input, Currency Input, Tag Input, Split Button, Multi Select, Sortable, and Tree.

Charts. Hand-rolled SVG charts cover bar, line, area, pie, donut, radar, radial bar, and scatter. They share ChartConfig, cascaded --color-<key> tokens, and zero JavaScript chart dependencies.

Timeline and Typography. A presentational Timeline and a Typography component round out the display primitives, wired to the same token system as the rest of the helm.

Dialog Service. ZitsDialogService lets an app await dialogs like function calls: ConfirmAsync, AlertAsync, and ShowAsync, rendered through one ZitsDialogOutlet on top of the brain's focus trap, scroll lock, and dismiss layer.

Motion

Motion package integration. Contract-based opt-ins make motion one class away. The Motion page documents the helm touch points and preset tiers, while the zero-JS baked-spring linear() easings ship as a static stylesheet.

Runtime theme engine

Generated theme CSS. ThemeStylesheet.Generate() writes zits-theme.css from C# using deterministic OKLCH ramps, fixed block order, invariant culture, and a committed-file drift guard.

Six-axis customizer. ZitsThemeService persists mode, base gray, primary, radius, font, and style recipe to localStorage, mirrors them to data-zits-* attributes, and restores full JSON selections before paint through zits-theme-init.js.

Switcher and scopes. ZitsThemeSwitcher provides a live popover customizer with a copyable CSS export. ZitsThemeScope lets any subtree carry its own theme, including forced light and forced dark islands.

Token fixes. The base token file defines --chart-1 through --chart-5 and font-family tokens so charts and typography have documented defaults.