# Lyra Design System — llms.txt > Lyra is an open source, CSS-first, white-label design system. A pure CSS core > (custom properties + `.lyra-*` classes) with thin React wrappers on top. > This file is the canonical reference for agents/LLMs generating UI with Lyra. ## Rules for generating Lyra code 1. NEVER hardcode a color, radius, shadow, font or spacing value — always use semantic tokens. 2. Components consume ONLY the semantic layer (`--accent`, `--surface-card`, `--text-muted`…), never the primitives (`--indigo-600`, `--slate-200`). 3. Dark mode: automatic via `[data-theme="dark"]` on `` — do not write manual dark styles. 4. White-label: brands define `--brand`, `--brand-contrast`, `--brand-radius`, `--brand-font` under `[data-brand="x"]` (see tokens/brand.css); the whole accent group is derived via color-mix. 5. In plain HTML use the classes: `.lyra-btn .lyra-btn--{primary|secondary|soft|ghost|danger} .lyra-btn--{sm|md|lg}`. In React use the components below — they emit the classes for you. 6. Focus: `box-shadow: var(--shadow-focus)` on `:focus-visible`; never a custom `outline`. 7. shadcn interop: import `tokens/compat-shadcn.css` AFTER styles.css (--background, --primary, --ring… are mapped). ## Semantic tokens (the layer you use) Colors: --accent, --accent-hover, --accent-active, --accent-soft, --accent-soft-text, --on-accent, --focus-ring, --surface-page, --surface-card, --surface-raised, --surface-sunken, --surface-overlay, --text-primary, --text-secondary, --text-muted, --text-faint, --text-inverse, --text-link, --border-default, --border-strong, --border-accent, --success, --success-soft, --success-text, --warning, --warning-soft, --warning-text, --danger, --danger-soft, --danger-text, --info, --info-soft, --info-text Spacing/radius/controls: --space-0, --space-1, --space-2, --space-3, --space-4, --space-5, --space-6, --space-8, --space-10, --space-12, --space-16, --space-20, --space-24, --radius-xs, --radius-sm, --radius-md, --radius-lg, --radius-xl, --radius-full, --control-sm, --control-md, --control-lg, --container-max, --sidebar-width, --content-gutter Typography: families --font-{sans,display,mono}; weights --weight-{regular..extrabold}; sizes --text-{xs..6xl} (UI default 14px = --text-base); composed styles for the `font` shorthand: --display-font, --h1-font, --h2-font, --h3-font, --body-font, --body-strong-font, --caption-font, --overline-font, --code-font Effects: --shadow-{xs,sm,md,lg,focus}; --duration-{fast,base,slow}; --ease-{out,in-out}; z-index --z-{dropdown,sticky,overlay,dialog,toast,tooltip}. ## React component API (@lyra-ds/react) ## Buttons ### Button ```ts /** * Props for {@link Button}. Extends the native ``. */ asChild?: boolean; } export declare function Button(props: ButtonProps): JSX.Element; ``` ### IconButton ```ts /** Props for {@link IconButton}. */ export interface IconButtonProps extends ButtonHTMLAttributes { /** Required accessible label, used for both `aria-label` and the native tooltip. */ label: string; /** Visual variant. Default `"secondary"`. */ variant?: 'primary' | 'secondary' | 'soft' | 'ghost' | 'danger'; /** Control size. Default `"md"` (40 × 40px). */ size?: 'sm' | 'md' | 'lg'; /** Icon content, normally an ``. */ children: ReactNode; } export declare function IconButton(props: IconButtonProps): JSX.Element; ``` ## Chrome ### Brand ```ts /** Props for {@link Brand}. */ export interface BrandProps { /** Image source used for the light theme mark. */ mark: string; /** Optional image source used for the dark theme mark. */ markDark?: string; /** Mark edge length in pixels. Sets `--brand-mark-size`. */ size?: number; /** Wordmark content that gives the brand its accessible name. */ /** Omit the wordmark to render a mark-only brand. */ /** A child link or framework routing element containing the wordmark. */ children?: ReactNode | undefined | ReactElement; /** Optional translated accessible name that overrides the wordmark text. */ /** Translated accessible name required when no wordmark is rendered. */ 'aria-label'?: string; /** Destination rendered as an anchor. Mutually exclusive with `asChild`. */ /** Destination is provided by the child element when `asChild` is enabled. */ href?: string | never; /** Render the native anchor or span. */ /** Render the single child element with the brand's props and classes merged. */ asChild?: false | true; } export declare function Brand(props: BrandProps): JSX.Element; ``` ### CodeBlock ```ts /** Props for {@link CodeBlock}. */ export interface CodeBlockProps extends HTMLAttributes { /** Optional language badge shown in the code panel bar. */ language?: string; /** Draw line numbers beside descendants whose class list includes `line`. */ lineNumbers?: boolean; /** Translated visible label for the copy button. Omit with `copiedLabel` to hide copying. */ copyLabel?: ReactNode; /** Translated visible label and polite announcement shown after a successful copy. */ copiedLabel?: ReactNode; /** Text copied instead of the rendered text content of this code block's `
`. */
  copyText?: string;
}
export declare function CodeBlock(props: CodeBlockProps): JSX.Element;
```

### Footer
```ts
/** Props for {@link Footer}. */
export interface FooterProps extends Omit, 'children'> {
  /** Optional brand content placed at the start of the footer row. */
  brand?: ReactNode;
  /** Optional supporting note placed after the brand. */
  note?: ReactNode;
  /** Optional resource links rendered inside the footer navigation landmark. */
  links?: ReactNode;
  /** Accessible name for the resource-links navigation landmark. */
  linksLabel?: string;
}
export declare function Footer(props: FooterProps): JSX.Element;
```

### Navbar
```ts
/** Props for {@link Navbar}. */
export interface NavbarProps extends Omit, 'children'> {
  /** Optional brand content placed at the start of the navigation row. */
  brand?: ReactNode;
  /** Optional primary navigation content rendered inside the navigation landmark. */
  nav?: ReactNode;
  /** Accessible name for the navigation landmark. */
  navLabel?: string;
  /** Optional controls placed at the end of the navigation row. */
  actions?: ReactNode;
  /** Keep the navbar fixed to the top while scrolling. Default `true`. */
  sticky?: boolean;
}
export declare function Navbar(props: NavbarProps): JSX.Element;
```

### NavLink
```ts
/** Props for {@link NavLink}. */
export interface NavLinkProps extends AnchorHTMLAttributes {
  /** Marks the destination as the current page. */
  active?: boolean;
  /** Render the single child element instead of an ``, preserving its routing behavior. */
  asChild?: boolean;
  /** Link content. Must be exactly one element when `asChild` is enabled. */
  children?: ReactNode;
}
export declare function NavLink(props: NavLinkProps): JSX.Element;
```

### SegmentedControl
```ts
/** Props for {@link SegmentedControl}. */
export interface SegmentedControlProps extends Omit, 'onChange'> {
  /** Options rendered in keyboard-navigation order. Provide at least two options. */
  options: SegmentedControlOption[];
  /** Currently selected option value. */
  value: string;
  /** Called with the next value after pointer or keyboard selection. */
  onChange: (value: string) => void;
  /** Translated accessible name for the radiogroup. */
  label: string;
}
export declare function SegmentedControl(props: SegmentedControlProps): JSX.Element;
```

### Shell
```ts
/** Props for {@link Shell}. */
export interface ShellProps extends HTMLAttributes {
  /** Optional navigation or complementary rail content. */
  sidebar?: ReactNode;
  /** Semantic element for the sidebar rail. Use `"nav"` when it contains primary navigation. */
  sidebarAs?: 'aside' | 'nav';
  /** Accessible name for the sidebar landmark. */
  sidebarLabel?: string;
  /** Optional top region placed before the main content. */
  topbar?: ReactNode;
  /** Semantic element for the main content. Use `"div"` when the shell is nested or embedded inside a page that already owns the `
` landmark. */ mainAs?: 'main' | 'div'; /** Optional complementary context rail content. */ aside?: ReactNode; /** Semantic element for the aside rail. Use `"nav"` when it contains navigation. */ asideAs?: 'aside' | 'nav'; /** Accessible name for the aside landmark. */ asideLabel?: string; /** Whether the document or the main region is the scroll container. Default: `"page"`. */ scroll?: 'page' | 'content'; /** Sidebar rail width in pixels. Sets `--shell-sidebar`. */ sidebarWidth?: number; /** Complementary aside rail width in pixels. Sets `--shell-aside`. */ asideWidth?: number; /** Sticky rail offset in pixels. Sets `--shell-top`. */ top?: number; } export declare function Shell(props: ShellProps): JSX.Element; ``` ### TableOfContents ```ts /** Props for {@link TableOfContents}. */ export interface TableOfContentsProps extends HTMLAttributes { /** In-page anchor links rendered in the contents rail. */ items: TableOfContentsItem[]; /** Id of the current in-page position. The component does not derive it from scroll state. */ activeId?: string; /** Visible heading and accessible name for the contents navigation landmark. */ label: string; } export declare function TableOfContents(props: TableOfContentsProps): JSX.Element; ``` ## Data ### EmptyState ```ts /** Props for {@link EmptyState}. */ export interface EmptyStateProps extends Omit, 'title'> { /** Optional illustrative icon content, normally an ``. */ icon?: ReactNode; /** Required empty-state heading. */ title: ReactNode; /** Optional explanatory text. */ description?: ReactNode; /** Optional action, normally a `