Installation#

@sigx/zero is the runtime. It renders anatomy and behavior and no styling, so you install it together with exactly one design system — a package that ships compiled CSS and a tiny runtime module. Two stylesheets and one function call is the whole setup.

Install the runtime and a design system#

Terminal
pnpm add @sigx/zero @sigx/zero-basic

@sigx/zero peer-depends on sigx (and the core packages the umbrella brings). Pick one design system:

PackageLookThemes
@sigx/zero-basicMonograph — paper surfaces, hairline structure, one petrol ink. Documentation-grade calm.basic (light), basic-dark
@sigx/zero-daisyuidaisyUI 5's palette and component look, role for role.light, dark, dim, nord, sunset

Both wire the same recommended vocabulary (eight colour roles, the xsxl size ramp), so switching between them later changes no component code. To build a look of your own instead, see Authoring a design system — the kit is a dev dependency, never a runtime one.

Wire the stylesheets#

TypeScript
// app entry
import '@sigx/zero/css';               // layer order + structural token fallbacks
import '@sigx/zero-basic/css';         // the design system: tokens + every recipe
import { installThemes } from '@sigx/zero-basic';

installThemes();                       // registers the design system's themes

@sigx/zero/css is the package's css/base.css: it declares the cascade layer order (@layer zero.fallback, zero.tokens, zero.recipes, zero.structure), design-system-neutral fallback values for the recommended tokens so an unstyled page is sane, and the zero.structure rule that keeps hidden parts hidden whatever a recipe says. Import it first. The design system's /css is its full compiled stylesheet — tokens, theme blocks and every recipe. Import order between the two does not matter for correctness (every compiled stylesheet restates the layer order), but base first is the convention.

installThemes() hands the design system's theme declaration to zero's theme registry, so themeController(), ThemeProvider and a theme picker know which themes exist and which scheme each has. Token values never pass through JavaScript — they are in the CSS. See Theming.

Granular imports#

A design system also exports its tokens alone and one file per component:

TypeScript
import '@sigx/zero-basic/css/tokens';   // tokens + theme blocks only
import '@sigx/zero-basic/css/tabs';     // one component's recipe
import '@sigx/zero-basic/css/dialog';

Useful when a page uses three components and you would rather ship three recipes.

Use a component#

Every component is its own subpath, and is also re-exported from the package root:

TSX
import { Dialog } from '@sigx/zero/dialog';
import { component } from 'sigx';

const Confirm = component(({ signal }) => {
    const state = signal({ open: false });
    return () => (
        <Dialog.Root model={() => state.open}>
            <Dialog.Trigger>Open</Dialog.Trigger>
            <Dialog.Popup>
                <Dialog.Title>Native top layer</Dialog.Title>
                <Dialog.Close>Close</Dialog.Close>
            </Dialog.Popup>
        </Dialog.Root>
    );
});

The subpath import (@sigx/zero/dialog) is the tree-shaking-friendly form; the root import (import { Dialog } from '@sigx/zero') is the same code.

Server rendering: SSR-safe ids#

Components mint ids for ARIA wiring (aria-controls, aria-labelledby, panel ids). On the server, register the zero plugin on the app so each request gets its own generator and the ids match on hydration:

TypeScript
import { zeroPlugin } from '@sigx/zero';

app.use(zeroPlugin());

In a browser-only app the default generator is fine. See Your first page for the full entry, including the first-paint theme script.

Typed vocabulary (optional)#

One side-effect import narrows every component's color / size / variant props to what the installed design system actually styles, and closes theme names on setTheme:

TypeScript
import '@sigx/zero-basic/register';

Without it, the props stay open unions with the recommended names autocompleting. See Typed vocabulary.

Next#