# 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. When omitted, the mark falls back to the initial * of the wordmark text (or of `aria-label` for a mark-only brand). */ 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; /** Soft-wrap code lines and break long tokens instead of allowing horizontal overflow. */ wrap?: 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' | 'div';
  /** Accessible name for the sidebar landmark. */
  sidebarLabel?: string;
  /** Optional top region placed before the main content. */
  topbar?: ReactNode;
  /** Page-level banner rendered before the navigation and outside the main landmark. */
  banner?: ReactNode;
  /** Optional keyboard skip link. Its href defaults to the main region's id. */
  skipLink?: {
    label: string;
    href?: string;
  };
  /** Id of the main region; generated when a skip link is provided without one. */
  mainId?: string;
  /** 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` for ordinary rails and page-scroll * Shells; a direct AppSidebar in a content-scroll rail owns its width instead. */ 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 ### DataTable ```ts /** Props for {@link DataTable}. */ export interface DataTableProps extends HTMLAttributes { /** Columns rendered in the supplied order. */ columns: DataTableColumn[]; /** Row records whose values may be any renderable React node. An `id` value is used for keys and selection. */ rows: RowShape[]; /** Table caption. Supply a meaningful name for each data set. */ caption?: ReactNode; /** Visually hide the caption while keeping it available to assistive technology. */ captionHidden?: boolean; /** Accessible name for the focusable scroll region when it differs from the table name. */ scrollLabel?: string; /** Controlled sorting state. Pass `null` for unsorted rows. */ sorting?: DataTableSorting | null; /** Initial sorting state when uncontrolled. Default: `null`. */ defaultSorting?: DataTableSorting | null; /** Called after sorting changes. */ onSortChange?: (sorting: DataTableSorting | null) => void; /** Whether to render row and select-all checkboxes. */ selectable?: boolean; /** Controlled selected row identifiers. */ selected?: Array; /** Initial selected row identifiers when uncontrolled. */ defaultSelected?: Array; /** Called after the selected row identifiers change. */ onSelectionChange?: (selected: Array) => void; /** Whether the header remains visible while the table scrolls. */ stickyHeader?: boolean; /** Maximum height for the scrollable table area. */ maxHeight?: number | string; /** Row density. Default: `"comfortable"`. */ density?: 'comfortable' | 'compact'; /** Whether to render loading placeholders, or the number of placeholder rows. */ loading?: boolean | number; /** Content shown instead of the default empty-state label. */ empty?: ReactNode; /** Content rendered below the scrollable table area. */ footer?: ReactNode; /** Whether rows highlight on hover. */ hover?: boolean; /** Labels for controls and the default empty state. Merged over the English defaults. */ labels?: DataTableLabels; } export declare function DataTable(props: DataTableProps): JSX.Element; ``` ### 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 `