# Kition Tessera > The design system for professional editors and Kition kits: design tokens (`@kition/tessera-tokens`), Tessera Icons (`@kition/tessera-icons`), and components (`@kition/tessera-ui`). ## Overview Getting started. Kition Tessera is the design system for professional editors: design tokens, Tessera Icons, and the components kits are built from. ### Three packages `@kition/tessera-tokens`: the Kit Harness Protocol theme tokens (`--kit-*`), component tokens, and skins (Paper, Graphite) as CSS variables, TypeScript, and Rust. `@kition/tessera-icons`: every icon as SVG path data on a 24 grid, as React components (`LayersIcon`), canvas drawing (`drawIcon`), SVG markup (`toSvg`), and the Rust crate `tessera-icons` for engines. `@kition/tessera-ui`: the components on these pages. They draw only through the theme tokens, so a host restyles all of them by sending one theme. ```tsx import '@kition/tessera-ui/styles.css' import { Button, ColorPicker } from '@kition/tessera-ui' import { LayersIcon } from '@kition/tessera-icons/react' ``` ### Principles Built for professional software: ribbons, docks, colour wheels, curves, timelines and meters sit beside buttons and fields. Styled only by tokens: no component hard-codes a colour, radius or shadow; skins and hosts change them all. One icon family: a 24 grid, a 1.5 stroke, round caps; tool icons carry accents in the skin colour. Accessible by default: labels, keyboard use, focus rings, and every skin held to WCAG AA contrast. ## Installation Getting started. Add the packages, import one stylesheet, and draw a first component; then apply a skin and give the components your strings. ### Install Components need React 19 or later. `@kition/tessera-ui` brings the tokens and the icons with it; add `@kition/tessera-icons` to import icons yourself, and `@kition/tessera-tokens` to read skins in code. Before the first npm release, depend on a checkout of kition-tessera next to your project, as Kition’s kits do: `"@kition/tessera-ui": "link:../kition-tessera/packages/ui"`, and the same for `packages/icons` and `packages/tokens`. The packages are TypeScript source, so use a bundler that compiles dependencies (Vite does). ```tsx pnpm add @kition/tessera-ui @kition/tessera-icons @kition/tessera-tokens ``` ### First component Import the stylesheet once, at the root of the app; it carries the Paper skin’s token values, so components draw without any other setup. Class names start with `kui-`. ```tsx import '@kition/tessera-ui/styles.css' import { Button, IconButton } from '@kition/tessera-ui' import { LayersIcon } from '@kition/tessera-icons/react' export function Toolbar() { return ( <> ) } ``` ### Apply a skin A skin is a colour scheme and one value per theme token. Set the tokens on the document root (or on any element, to skin only what is inside it) and mark the colour scheme. A kit does not do this itself: its host sends the theme (see Theming and skins). ```tsx import { SKINS } from '@kition/tessera-tokens' const theme = SKINS.graphite const root = document.documentElement for (const [name, value] of Object.entries(theme.tokens)) root.style.setProperty(name, value) root.dataset.colorScheme = theme.colorScheme ``` ### Strings Without a provider, components speak English. Wrap the app in `StringsProvider` for another language (`zh-CN` is included) or your own wording; see Strings and elements. ```tsx import { StringsProvider, TESSERA_CATALOGS, createStrings } from '@kition/tessera-ui' ``` ### Rules for code that uses Tessera Take colours, radii, fonts and shadows from the tokens (`var(--kit-primary)`), never as literals, so every skin applies. Use the Tessera component when there is one (Button, IconButton, Modal, Popover, Select, NumberField) instead of styling a raw element. Give every icon-only control a label; take icons from Tessera Icons so strokes match. ## Building with an AI assistant Getting started. Give a coding assistant Tessera’s docs as Markdown, and it writes an editor’s interface with the right components, props and tokens. ### What to give it Every guide and component page is also a Markdown file with the same content: what the component is, when to use it and when not to, each example as a complete file, and its props with their types and values. An assistant that reads the web: point it at `https://tessera.kition.ai/llms.txt` (an index, one line per page, each linking to its Markdown) or at `https://tessera.kition.ai/llms-full.txt` (the whole reference in one file). An assistant that works in your repository: check out kition-tessera next to your project and let it read `docs/README.md`, then `docs/components/.md` for the component it needs, `docs/icons.md` to find an icon by what it means, and `docs/tokens.md` for the tokens. On this site, every page has a Copy for AI button: the page as Markdown, or a prompt that points at it. ### A prompt that works Name the components you expect, point at the docs, and state the three rules. Assistants follow rules that are written down. ```tsx Build the layers panel of a photo editor with Kition Tessera. Read first: https://tessera.kition.ai/llms-full.txt Use Panel, PanelFooter, EyeButton, Thumbnail, IconButton and NumberField from @kition/tessera-ui, and icons from @kition/tessera-icons/react. Rules: - Use a Tessera component where there is one; do not style a raw ) } ``` ### Example: Sizes Without a size the button keeps the 30px of editor chrome. ```tsx import { Button } from '@kition/tessera-ui' export default function Demo() { return (
) } ``` ### Example: Loading, icons, icon only Icons inside a button draw at 16px; an icon-only button is square and needs an aria-label. ```tsx import { useState } from 'react' import { Button } from '@kition/tessera-ui' import { PlusIcon, SettingsIcon } from '@kition/tessera-icons/react' export default function Demo() { const [saving, setSaving] = useState(false) return (
) } ``` ### Example: Links drawn as buttons ```tsx import { ButtonLink } from '@kition/tessera-ui' import { ArrowLeftIcon, MailIcon } from '@kition/tessera-icons/react' export default function Demo() { return (
Sign in again Back to the console Contact support
) } ``` ### Button props A button. Its `className` adds to Tessera's, so a host can adjust one button's layout. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | `ButtonVariant`: `'danger'`, `'primary'`, `'secondary'`, `'subtle'`, `'ghost'`, `'danger-outline'` | | | | `size` | `ControlSize`: `'sm'`, `'md'`, `'lg'` | | Without `size` a button keeps the editor chrome's 30px. | | `iconOnly` | `boolean` | | A square button holding only an icon; give it an `aria-label`. | | `loading` | `boolean` | | Shows a spinner before the label and marks the button busy, while its action runs. | Also takes the attributes of its HTML element (`className`, `aria-*`, events). ### ButtonLink props A link that looks like a button: for navigation (another page, a sign-in URL, a mail link) drawn as an action. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | `ButtonVariant`: `'danger'`, `'primary'`, `'secondary'`, `'subtle'`, `'ghost'`, `'danger-outline'` | | | | `size` | `ControlSize`: `'sm'`, `'md'`, `'lg'` | | | | `render` | `(props: AnchorHTMLAttributes & { className: string; children?: ReactNode }) => ReactNode` | | Draws the link another way: a router passes its own (`(props) => `). | Also takes the attributes of its HTML element (`className`, `aria-*`, events). ## Spinner General. A spinning circle for work in progress. ```ts import { Spinner } from '@kition/tessera-ui' ``` ### When to use - Inside a button while its action runs (Button `loading`). - Next to a status that is still updating. ### When not to - Long work with known progress: show the progress. ### Example: Sizes and a label ```tsx import { Spinner } from '@kition/tessera-ui' export default function Demo() { return (
Syncing…
) } ``` ### Spinner props A spinning circle for work in progress; `label` names it for screen readers (otherwise it is decorative). | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | `number` | `16` | | | `label` | `string` | | | | `className` | `string` | | | ## IconButton General. An icon-only button with an accessible label; `pressed` makes it a toggle. ```ts import { IconButton } from '@kition/tessera-ui' ``` ### When to use - Toolbars, tool rails, panel headers. ### When not to - An action whose icon is not obvious: use a Button with a label. ### Example: Toggles in a bar ```tsx import { useState } from 'react' import { IconButton } from '@kition/tessera-ui' import { BoldIcon, ItalicIcon, UnderlineIcon } from '@kition/tessera-icons/react' export default function Demo() { const [bold, setBold] = useState(true) return (
setBold(!bold)} />
) } ``` ### IconButton props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `icon` (required) | `IconComponent` | | | | `label` (required) | `string` | | | | `pressed` | `boolean` | | | Also takes the attributes of its HTML element (`className`, `aria-*`, events). ## Badge General. A small count or status beside a label. ```ts import { Badge } from '@kition/tessera-ui' ``` ### When to use - The number of records in a view. - A Beta or New mark. ### When not to - An action: use a Button. ### Example: Count and status ```tsx import { Badge } from '@kition/tessera-ui' export default function Demo() { return (
Grid view 128 AI fields Beta
) } ``` ### Badge props A small count or status beside a label (records in a view, a beta mark). Also takes the attributes of its HTML element (`className`, `aria-*`, events). ## Card General. A product card: 12px radius, a hairline, a light shadow. ```ts import { Card, CardHeader, CardContent } from '@kition/tessera-ui' ``` ### When to use - Grouping settings or a summary on a page. ### Example: Header and content ```tsx import { Button, Card, CardContent, CardHeader } from '@kition/tessera-ui' export default function Demo() { return ( Model Claude Opus · 1,240 credits this month ) } ``` ### Card props A product card: 12px radius, a hairline, a light shadow. Also takes the attributes of its HTML element (`className`, `aria-*`, events). ### CardHeader props Also takes the attributes of its HTML element (`className`, `aria-*`, events). ### CardContent props Also takes the attributes of its HTML element (`className`, `aria-*`, events). ## Disclosure General. A section that opens and closes under its title. ```ts import { Disclosure } from '@kition/tessera-ui' ``` ### When to use - Advanced settings most people do not need. ### Example: Closed and open ```tsx import { Disclosure, TextInput } from '@kition/tessera-ui' export default function Demo() { return (
1,240 credits this month
) } ``` ### Disclosure props A section that opens and closes under its title. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `title` (required) | `ReactNode` | | | | `defaultOpen` | `boolean` | `false` | | | `open` | `boolean` | | Open, when the screen holds the state (with `onOpenChange`). | | `onOpenChange` | `(open: boolean) => void` | | | | `onClose` | `() => void` | | Called when the person closes it. | | `children` | `ReactNode` | | | | `className` | `string` | | | ## TextInput Forms. A single-line text field in three sizes: sm (toolbars), md (panels), lg (forms). ```ts import { TextInput } from '@kition/tessera-ui' ``` ### Example: Sizes and invalid ```tsx import { TextInput } from '@kition/tessera-ui' import { SearchIcon } from '@kition/tessera-icons/react' export default function Demo() { return (
} />
) } ``` ### TextInput props A single-line text field. `invalid` marks it (and `aria-invalid`) after a failed check. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | `ControlSize`: `'sm'`, `'md'`, `'lg'` | `'sm'` | | | `invalid` | `boolean` | | | | `prefix` | `ReactNode` | | An icon (or short text) inside the field before the text: a search glass, a person. | | `wrapperClassName` | `string` | | Classes for the box around the field and its prefix (layout: width, margins). | Also takes the attributes of its HTML element (`className`, `aria-*`, events). ## PasswordInput Forms. A password field with a show and hide button outside the tab order. ```ts import { PasswordInput } from '@kition/tessera-ui' ``` ### Example: Show and hide ```tsx import { PasswordInput } from '@kition/tessera-ui' export default function Demo() { return } ``` ### PasswordInput props A password field with a show/hide button; the button keeps out of the tab order. `className` goes on the field itself, as on TextInput. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | `ControlSize`: `'sm'`, `'md'`, `'lg'` | `'sm'` | | | `prefix` | `ReactNode` | | An icon (or short text) inside the field before the text: a search glass, a person. | | `invalid` | `boolean` | | | | `wrapperClassName` | `string` | | Classes for the box around the field and its show/hide button (layout: width, margins). | Also takes the attributes of its HTML element (`className`, `aria-*`, events). ## Textarea Forms. Multi-line text; with autoSize it grows with its text (useAutoSize does the same for a text area of your own). ```ts import { Textarea } from '@kition/tessera-ui' ``` ### Example: Fixed and growing ```tsx import { useState } from 'react' import { Textarea } from '@kition/tessera-ui' export default function Demo() { const [note, setNote] = useState('Grows as you type, up to five lines.') return (