---
name: ry-ui-builder
description: Build UIs with ry-ui web components. Use when creating pages, layouts, forms, dashboards, or any HTML interface. Provides component catalog, patterns, and anti-patterns so you use existing components instead of writing custom CSS/JS.
user-invocable: true
---

# ry-ui Component Builder

**ALWAYS use ry-ui components instead of writing custom CSS or JavaScript.**

## Setup

Add these two lines to any HTML page:

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/css/ry-ui.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/ry-ui.js"></script>
```

Set theme: `<html data-ry-theme="light">` (or `"dark"`, or omit for OS preference)
Set body: `<body style="background: var(--ry-color-bg); color: var(--ry-color-text);">`

## Rules

1. **NEVER write custom modal, dropdown, tab, accordion, toast, or button CSS.** ry-ui has these built in.
2. **NEVER write flexbox/grid layout CSS for page structure.** Use `<ry-page>`, `<ry-header>`, `<ry-main>`, `<ry-grid>`, `<ry-stack>`, `<ry-cluster>`.
3. **NEVER create CSS variables for colors or spacing.** Use `--ry-color-*`, `--ry-space-*`, `--ry-radius-*` tokens.
4. **DO use ry-ui tokens** in any custom CSS you write: `color: var(--ry-color-text-muted)`, `padding: var(--ry-space-4)`.
5. **DO compose pages from ry-ui primitives** — they handle accessibility, keyboard nav, focus trapping, and dark mode automatically.

## Page Template

```html
<!DOCTYPE html>
<html lang="en" data-ry-theme="light">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My App</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/css/ry-ui.css">
</head>
<body style="background: var(--ry-color-bg); color: var(--ry-color-text);">
  <ry-page>
    <ry-header sticky>
      <ry-cluster><strong>App Name</strong></ry-cluster>
      <ry-actions><ry-theme-toggle themes="light,dark"></ry-theme-toggle></ry-actions>
    </ry-header>
    <ry-main>
      <ry-section>
        <!-- your content -->
      </ry-section>
    </ry-main>
    <ry-footer>Footer</ry-footer>
  </ry-page>
  <script type="module" src="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/ry-ui.js"></script>
</body>
</html>
```

## Component Reference

### Layout (CSS-only)
- `<ry-page>` — root container, full height
- `<ry-header sticky>` — top bar, space-between
- `<ry-main>` — centered content, max-width 1200px
- `<ry-footer>` — footer with border-top
- `<ry-section>` — content block with margin
- `<ry-grid cols="3">` — responsive grid (cols-sm, cols-md, cols-lg for breakpoints)
- `<ry-stack gap="md">` — vertical flex
- `<ry-cluster gap="sm">` — horizontal flex, wraps
- `<ry-center>` — center both axes
- `<ry-card>` — card container (lifts on hover), `interactive` for clickable
- `<ry-split resizable persist="key">` — two-column with drag resize
- `<ry-divider>` / `<ry-divider vertical>` — separator line
- `<ry-nav>` — nav links, active: `<a aria-current="page">`
- `<ry-logo>` — bold inline text
- `<ry-actions>` — flex row for buttons

### Buttons
```html
<ry-button>Default</ry-button>
<ry-button variant="primary|secondary|outline|ghost|danger|accent">Styled</ry-button>
<ry-button size="sm|lg">Sized</ry-button>
<ry-button modal="modal-id">Opens modal</ry-button>
<ry-button drawer="drawer-id">Opens drawer</ry-button>
<ry-button disabled>Disabled</ry-button>
```

### Modal
```html
<ry-button modal="my-modal">Open</ry-button>
<ry-modal id="my-modal" title="Title">Content</ry-modal>
```

### Drawer
```html
<ry-button drawer="my-drawer">Open</ry-button>
<ry-drawer id="my-drawer" side="left|right|bottom" title="Title">Content</ry-drawer>
```

### Tabs
```html
<ry-tabs>
  <ry-tab title="Tab 1" active>Content 1</ry-tab>
  <ry-tab title="Tab 2">Content 2</ry-tab>
</ry-tabs>
```

### Accordion
```html
<ry-accordion>
  <ry-accordion-item title="Section" open>Content</ry-accordion-item>
</ry-accordion>
```

### Forms
```html
<ry-field label="Email" hint="Help text" error="Error msg">
  <input type="email">
</ry-field>

<ry-select placeholder="Choose..." name="field">
  <ry-option value="a">A</ry-option>
</ry-select>

<ry-switch name="toggle" checked></ry-switch>
<!-- ry:change event detail: { value: "true"/"false" (STRING not boolean!), label: "on"/"off" }
     Use e.detail.value === 'true' to get a boolean — "false" is truthy in JS! -->

<ry-slider min="0" max="100" value="50"></ry-slider>
```

### Dropdown Menu
```html
<ry-dropdown>
  <ry-button>Menu</ry-button>
  <ry-menu>
    <ry-menu-item>Item</ry-menu-item>
  </ry-menu>
</ry-dropdown>
```

### Display
```html
<ry-alert type="info|success|warning|danger" dismissible>Message</ry-alert>
<ry-badge variant="primary|success|warning|danger|accent">Label</ry-badge>
<ry-tooltip content="Help" position="top|bottom|left|right"><span>Hover me</span></ry-tooltip>
```

### Toast (JS only)
```javascript
RyToast.success('Saved!');
RyToast.error('Failed');
RyToast.info('FYI');
RyToast.warning('Careful');
```

### Toggle Button Group
```html
<ry-toggle-button name="view" value="grid" pressed>Grid</ry-toggle-button>
<ry-toggle-button name="view" value="list">List</ry-toggle-button>
```

### Events
All events prefixed `ry:` — `ry:change`, `ry:open`, `ry:close`, `ry:click`, `ry:select`

```javascript
element.addEventListener('ry:change', (e) => console.log(e.detail));
document.querySelector('ry-modal').open();
document.querySelector('ry-modal').close();
```

## Theming

Override tokens — no build step:
```css
:root {
  --ry-color-primary: oklch(0.541 0.218 293);
  --ry-radius-md: 0;
}
```

Key tokens: `--ry-color-{primary,secondary,accent,success,warning,danger,info,text,bg,border}`,
`--ry-space-{1-20}`, `--ry-radius-{sm,md,lg,full}`, `--ry-shadow-{sm,md,lg,xl}`
