Zero#

Zero splits a UI into two artifacts that evolve independently: headless components that render a stable, machine-readable anatomy and no styling, and a design system — typed tokens and per-part recipes — compiled to plain, layered CSS that selects on that anatomy. Swapping the whole look of an app is an import swap. Generating a new look is something a model, or a human afternoon, can do against the published manifest.

v0.2.0-beta.1 MIT

TSX
import { Tabs } from '@sigx/zero/tabs';

<Tabs.Root model={() => state.tab}>
    <Tabs.List>
        <Tabs.Tab value="a">First</Tabs.Tab>
        <Tabs.Tab value="b">Second</Tabs.Tab>
    </Tabs.List>
    <Tabs.Panel value="a">…</Tabs.Panel>
    <Tabs.Panel value="b">…</Tabs.Panel>
</Tabs.Root>
TypeScript
// The entire skin of the app:
import '@sigx/zero/css';                    // layer order + structural fallbacks
import '@sigx/zero-daisyui/css';            // ← or '@sigx/zero-basic/css', or yours
import { installThemes } from '@sigx/zero-daisyui';
installThemes();

The four packages#

PackageWhat it is
@sigx/zeroThe runtime: the anatomy contract, the headless behaviors (controllable models, SSR-safe ids, roving focus, dismissal, positioning, press feedback), 51 components, the theme engine, and the anatomy manifest.json + llms.txt. Peer-depends on sigx only.
@sigx/zero-kitThe Node-only authoring kit: defineTokens / defineRecipe / defineDesignSystem / defineApi, the tokens + recipes → CSS compiler, validation, the sigx zero:build / zero:validate CLI plugin, the JSON Schemas and the design-system generation skill. Never a runtime dependency.
@sigx/zero-basicThe neutral starter design system — readable defaults from day one, and the reference input for generating your own.
@sigx/zero-daisyuidaisyUI's tokens and component look as pure data — five themes, no Tailwind, no plugin — plus a daisy-native typed ./components surface.

All four publish in lockstep at one version.

Why zero is different#

Models, not prop triplets. sigx two-way binding replaces value / defaultValue / onValueChange with one optional model: <Dialog.Root model={() => state.open}>. A component with more than one piece of state binds the extras as named models (model:inputValue). See Models.

Native platform first. <dialog> and the top layer mean no Portal, and free focus trapping, Escape and focus restore. <details> disclosure works with no JavaScript. Form controls are real inputs that post a form before hydration. The popover attribute lifts menus and popovers into the top layer. Zero adds the anatomy and the keyboard; the platform does the rest.

The anatomy is a contract. Every part carries data-scope / data-part and at most one data-state; flags are presence-only; states, flags and placements come from closed, governed vocabularies. Every component ships its parts × states × token hints as JSON, so recipes type-check against it, tests assert against it, and a generator can write a design system having read nothing else. A part rename is a breaking change, and the build says so. See The anatomy contract.

A design system is data. Tokens and recipes compile to four cascade layers of plain CSS — no Tailwind, no CSS-in-JS, no runtime styling engine — and a component the design system has never heard of renders unstyled but accessible. That fallback is the baseline of the whole idea, not an error state. See Authoring a design system.

Typed to the design system you use. One import of a design system's generated /register module narrows every color / size / variant prop to exactly what its compiled CSS answers to. A design system that declares an api also ships a ./components module with the vendor's own prop names. See Typed vocabulary and Vendor-named component APIs.

One token vocabulary across web and Lynx. The contract is not web-shaped: the same design-system source compiles to a class-grammar target for @sigx/lynx-zero, so one tokens.ts + recipes.ts can skin a native app too. See Lynx.

Where to go next#