A lattice is an invisible grid that gives things their shape. Latty is that grid for your product.
Framework-agnostic design system built on design tokens and Web Components. One token change cascades through every component in every framework — no re-theming, no duplication.
Docs: https://latty-ds.com
-
Token-first — a single
tokens.config.jsondrives CSS variables, JSON, and JS exports; full OKLCH colour palettes generated automatically. -
Any framework — components ship as standard Web Components (
lt-*); React wrappers are auto-generated from the same manifest. -
Themeable at runtime or build time — call
configure()in the browser to swap palettes on the fly, or usecreateStyleSheet()at build time to inject tokens with zero flash of unstyled content. - Accessible by default — every component is tested with axe-core and validated with markuplint.
- Monorepo, batteries included — tokens, web components, icons, React wrappers, utilities, and a live documentation site all in one repo.
| Package | Description |
|---|---|
@latty-ds/tokens |
Design tokens → CSS variables, JSON, and JS exports |
@latty-ds/web |
Web Components (lt- prefix, built with Lit) |
@latty-ds/icons |
Icon components with pluggable provider system |
@latty-ds/react |
React wrappers auto-generated from the web manifest |
@latty-ds/utils |
Shared internal utilities |
pnpm add @latty-ds/tokens @latty-ds/web
# or: npm install @latty-ds/tokens @latty-ds/webImport the token CSS once at the root of your app:
import '@latty-ds/tokens/dist/tokens.css';
import '@latty-ds/web';<lt-button variant="primary">Save changes</lt-button>
<lt-textfield label="Email" type="email" required></lt-textfield>
<lt-badge variant="success">Active</lt-badge>pnpm add @latty-ds/reactimport { Button, Textfield, Badge } from '@latty-ds/react';
<Button variant="primary">Save changes</Button>
<Textfield label="Email" type="email" required />
<Badge variant="success">Active</Badge>Web Components work natively in Vue — no extra package needed:
<template>
<lt-button variant="primary" @click="save">Save changes</lt-button>
<lt-textfield label="Email" type="email" required></lt-textfield>
</template>Latty exposes a configure() API for runtime theming — useful for white-labelling, dark mode, or per-tenant colour schemes:
import { configure } from '@latty-ds/tokens/configure';
configure({
colors: { primary: '#7c3aed' },
font: { family: 'Inter, sans-serif' },
border: { radius: '0.5rem' }
});For zero flash of unstyled content at build time (Astro, Next.js, etc.), use createStyleSheet() and inject the result into your <head> before any components render:
import { createStyleSheet } from '@latty-ds/tokens/configure';
const css = createStyleSheet({ colors: { primary: '#7c3aed' } });
// inject as <style> in <head>The agents/ directory is a self-contained context pack for AI coding agents (Claude, Cursor, etc.) building applications with Latty. Download or copy it into a consuming project and point your agent's system prompt, rules file, or project instructions at agents/README.md — it covers installation, framework-specific usage, theming, the full component catalog, a task-to-component decision guide, and composition patterns, all written for a consumer's perspective rather than a Latty contributor's.
| File | Covers |
|---|---|
agents/README.md |
Entry point — what's in the pack and how to use it |
agents/installation.md |
Installing packages and registering components |
agents/usage.md |
Vanilla/React/Vue/Svelte usage, slots, events, forms |
agents/theming.md |
configure()/createStyleSheet(), colors, fonts, dark mode |
agents/components.md |
Full component catalog and shared prop vocabulary |
agents/decision-guide.md |
Which component fits a given UI task |
agents/patterns.md |
Real multi-component composition recipes |
It's deliberately not a full API reference — for exact per-component props/slots/events, agents are pointed at custom-elements.json, which ships with the published @latty-ds/web package.
Prerequisites: Node.js ≥ 24, pnpm.
pnpm install # install all workspace dependencies
pnpm dev # build tokens + manifest, then start docs at localhost:4321
pnpm test # run the full test suite (Vitest)
pnpm build # build all packages
pnpm typecheck # TypeScript type-check across the monorepo
pnpm lint # ESLint (packages only — run pnpm eslint docs/src for docs)Additional tools:
pnpm codegen:wrappers # regenerate React wrappers after changing web components
pnpm bundle-size # print per-component gzip sizes vs baseline
pnpm lint:markup # markuplint accessibility checks on the docs site
pnpm a11y # pa11y-ci full-page accessibility audit (requires live server)packages/
tokens/ # tokens.config.json → CSS vars, JSON, JS (OKLCH palette generation)
web/ # Lit-based Web Components; builds custom-elements.json manifest
icons/ # Iconoir-based icons with pluggable provider
react/ # React wrappers (auto-generated from custom-elements.json)
utils/ # shared utilities — no external deps
docs/ # Astro documentation site with live component demos
scripts/ # codegen, bundle analysis, boundary checks
Package boundary rule: within a package use relative imports; across packages use the declared workspace:* package name. A check:boundaries script (also runs on git push) enforces this.
- Fork and clone the repo.
- Install dependencies:
pnpm install. - Create a feature branch.
- Make changes, run
pnpm test && pnpm typecheck && pnpm lint. - Commit following Conventional Commits (
feat,fix,docs, etc.) — a commit-msg hook enforces this. - Open a pull request.
To scaffold a new component: /new-component <Name> (via Claude Code) — generates the web component, tests, docs page, and sidebar entry in one step.
MIT