Krizaka
All building blocks

krizaka-ui

Krizaka UI

Tokens, a Tailwind v4 preset, accessible primitives, icons and i18n — web and React Native.

The problem it removes

Three products, three token vocabularies, 1,153 light: overrides in one app.

Three products, three token vocabularies: we measured 1,153 light: overrides in one application, the same card written five times, and focus traps, keyboard handling and ARIA rewritten by hand in each kit.

  • A theme implemented as light: and dark: variants in every component — a new theme means touching all of them.
  • Accessibility rewritten per product, and wrong in at least one.
  • A documentation site that describes last quarter's props.

What it does

  • One semantic vocabulary, --kz-*, compiled from design tokens — dark and light alike.
  • Accessible primitives with React Native parity, one entry point each.
  • Every component's documentation generated from its code.

One semantic vocabulary (--kz-*) compiled from design tokens, a preset that turns it into Tailwind utilities, and primitives — button, card, dialog, field, tabs, toast, command palette… — with React Native parity, one entry point each. The documentation of every component is generated from its code.

The owl reads the code, not a wiki: every component's page on krizaka.com/docs/ui is generated from its meta.ts and its named examples, and the registry tests fail when one is missing.

The owl's rule

Decisions and trade-offs

  1. We chose

    One token vocabulary; dark on :root, light on html.light; a brand overrides values (brands/scoped.css).

    We refused

    light:/dark: variants in components, and a token set per product.

    Because

    A theme or a brand is a set of values: Orazaka's orange and Orochia's violet use the same components as this site.

    What it costs you

    Components read var(--kz-*) only; raw palette colours are refused by the lint rules.

  2. We chose

    Radix for every non-trivial interaction, variants with tailwind-variants, every story audited by axe in dark and light on each pull request.

    We refused

    Hand-written focus traps and keyboard handling.

    Because

    Accessibility is written once and tested where it is written.

    What it costs you

    Radix in your bundle; size-limit budgets per entry keep it in check.

  3. We chose

    Words arrive as props; no translation function inside the library.

    We refused

    Bundling a translation runtime.

    Because

    Any i18n works — ours (@krizaka/i18n, typed catalogues and a CI check) or yours.

    What it costs you

    You pass the labels.

  4. We chose

    A ratchet: per-repository counters of raw palette classes, light: variants, [var(--…)] utilities and className templates that may only go down.

    We refused

    A big-bang migration, and a lint rule switched on at once.

    Because

    An existing application adopts it screen by screen without letting the debt grow back.

    What it costs you

    A lint-ratchet.json to commit and a check in CI.

In code

tsxapp/globals.css · Save.tsx
/* globals.css — your brand is values, never components */
@import "tailwindcss";
@import "@krizaka/tailwind";        /* tokens + utilities + motion signature */
@import "@krizaka/ui/tailwind.css";
:root      { --kz-accent: hsl(152 62% 40%); }   /* dark is the default */
html.light { --kz-accent: hsl(152 70% 30%); }

// Save.tsx — one entry point per primitive: an app ships only what it imports
import { Button } from "@krizaka/ui/button";

export function Save({ label }: { label: string }) { // words arrive as props: any i18n works
  return <Button variant="primary">{label}</Button>;
}

Don't use it when

  • You don't use Tailwind v4: the preset requires it (the tokens alone are plain CSS variables).
  • You want an unstyled kit and own every pixel: use Radix directly.
  • You need charts today: @krizaka/charts is being built.

Where it stands

@krizaka/ui, tokens and tailwind 2.2.0 on npm (latest) — 2.2.0 brought the five birds of this page (@krizaka/ui/mascots); icons, i18n, intl and config 0.1.0. Supported: majors N and N-1, fixes for six months after N+1.

Published

In progress

  • @krizaka/charts — theme- and brand-aware charts on Apache ECharts, each with an accessible data table, and the effects and blocks after it: the roadmap is an open epic.krizaka-ui#49

Adopt it

bashterminal
npm install @krizaka/ui @krizaka/tailwind @krizaka/tokens tailwindcss
# the debt counters of an existing app (raw palette, light:, [var(--…)], className templates):
npx -p @krizaka/config krizaka-ratchet --json --root .

Tell us where it hurts.

A block is right when it survives your code base, not ours. Ask in the block's thread, propose a change as an idea, or report a bug on its repository — every decision on this page is open to a better argument.

The other blocks