Skip to main content

Introduction

ZUI is a layered system for building complex UI. The premise: most of the cost of a complex screen is in layers every product rebuilds, a theme, a component set, and the large composites on top (editors, tables, dashboards). Factor those layers into packages with one shared contract and the composites become reusable across products with different visual identities.

The contract is a fixed set of CSS custom properties. Every package reads them, and every colour, radius and shadow in every package comes from them.

Released

PackageVersionWhat it is
@zuilib/tokens0.1.0The contract. One CSS file of custom properties for colour, radius, shadow and motion, with light and dark values. Components read the names; themes override the values. Pure CSS, optional Tailwind v4 mapping.
@zuilib/text-editor0.11.1The first composite. A markdown editor for React built on Lexical: tables, an embedded diagram canvas, highlighted code, outline, section folding. The document model is a controlled markdown string, and that string is the whole format.

Both are ESM with TypeScript types, published under the @zuilib scope.

Release order follows dependency order. Tokens first, because theming a component needs a shared name for every property it uses. The editor second, as the first composite on the contract and a test of it. A theme is a set of value overrides, and the editor takes those overrides as is.

Next

A components package is in progress: the primitive set on the same token contract, so one theme covers primitives and composites alike. Further packages follow until the set covers a full frontend toolkit. Each ships with a guide per feature and a changelog.

Install

# Tokens only
pnpm add @zuilib/tokens

# The editor (tokens recommended; Lexical packages are peers)
pnpm add @zuilib/text-editor @zuilib/tokens \
lexical @lexical/react @lexical/markdown @lexical/rich-text \
@lexical/code @lexical/list @lexical/link @lexical/table @lexical/utils

One theme, two modes

Every ZUI package reads the same custom properties (--primary, --background, --border, --radius, --shadow-medium, …). Light values live on :root; dark values are overrides under a .dark class. Dark mode is one line in your app:

document.documentElement.classList.toggle('dark', isDark)

The .dark class has to sit on <html> (or an ancestor of everything you theme): the tokens resolve where they are declared, so a .dark wrapper lower in the tree only affects its own subtree. This site works that way: use the toggle in the navbar and every embedded editor follows.

Where next

  • Tokens: entry points, setup with and without Tailwind, retheming.
  • Themes: eight looks for this site and its examples, each a handful of overrides; pick one from the navbar.
  • Token reference: every custom property with its light and dark value.
  • Text editor: install, quick start, and a guide per feature.