# The prototype kit

The header a prototype loads, the ten component classes it can use, and the rules that keep every agent-written prototype looking like one product.

Source: https://codeherder.com/docs/prototype-kit/

The header a prototype loads, the ten component classes it can use, and the rules that keep every agent-written prototype looking like one product.

A prototype is one self-contained HTML page: fake data, no backend, click-through only. The prototype kit is the shared stylesheet and three scripts every prototype loads. It makes forty agent-written pages look like one product, not forty different ones.

## The header

Add these four lines to the prototype’s `<head>`:

```
<link rel="stylesheet" href="https://preview.codeherder.com/kit/tokens.css">
<script src="https://preview.codeherder.com/kit/tailwind.js"></script>
<script defer src="https://preview.codeherder.com/kit/alpine.js"></script>
<script defer src="https://preview.codeherder.com/kit/bridge.js"></script>
```

`tokens.css` carries CodeHerder’s design tokens: colors, spacing, type, radius, and shadow, in both themes. `tailwind.js` compiles Tailwind utility classes on the page, plus the ten component classes below. `alpine.js` gives you `x-data` for state. `bridge.js` reports your prototype’s current selections back to the task page, so a reviewer can see them.

Use these exact, absolute URLs. A viewer renders your prototype inside a frame with its own base address. A relative path resolves to the wrong place there.

## The ten component classes

Each class works two ways: on its own, or combined with a Tailwind utility class. The utility class overrides one property, such as a color or a size. Add it after the component class in the `class` attribute.

**`proto-btn`** — a button.

```
<button type="button" class="proto-btn">Cancel</button>
<button type="button" class="proto-btn bg-cta text-white border-cta">Save</button>
```

**`proto-input`** — a text input.

```
<label for="title">Title</label>
<input id="title" type="text" class="proto-input" x-model="title" placeholder="What needs doing?">
```

**`proto-select`** — a dropdown.

```
<label for="status">Status</label>
<select id="status" class="proto-select" x-model="status">
  <option value="done">Done</option>
</select>
```

**`proto-badge`** — a status pill. Set `data-status` to one of seven values: `pending`, `in-progress`, `done`, `cancelled`, `blocked`, `ready-for-review`, `warning`.

```
<span class="proto-badge" data-status="done">Done</span>
<span class="proto-badge" data-status="blocked">Blocked</span>
```

**`proto-card`** — a bordered, padded panel.

```
<div class="proto-card">
  <h2 class="text-lg font-semibold">Usage this month</h2>
</div>
```

**`proto-table`** — a dense data table.

```
<table class="proto-table">
  <thead><tr><th scope="col">Title</th><th scope="col">Status</th></tr></thead>
  <tbody><tr><td>Ship it</td><td>Done</td></tr></tbody>
</table>
```

**`proto-dialog`** — a modal panel. Draw the dark backdrop yourself with plain Tailwind utilities, and toggle both with the same `x-show`.

```
<div class="fixed inset-0 flex items-center justify-center bg-black/50" x-show="dialogOpen" x-cloak>
  <div class="proto-dialog" role="dialog" aria-modal="true">Content</div>
</div>
```

**`proto-tabs`** — a tab strip.

```
<nav class="proto-tabs" role="tablist" aria-label="View">
  <button type="button" role="tab" aria-selected="true">All</button>
  <button type="button" role="tab" aria-selected="false">Mine</button>
</nav>
```

**`proto-empty`** — an empty-state block.

```
<div class="proto-empty">
  <p>No tasks match this filter.</p>
</div>
```

**`proto-toast`** — a floating notification.

```
<div class="proto-toast" x-show="toast" x-cloak x-text="toast"></div>
```

## The rules

Follow these rules so your prototype opens correctly and renders like every other one.

- **Write one file.** Put your markup, your styles, and your script in a single `.html` file.
- **Put your data inline.** Write your fake records as a JavaScript object in the file. Do not fetch data from a server.
- **Make no network calls.** The frame blocks every request except the four kit files. A `fetch` call, an image from a CDN, or an embedded video will not load.
- **Never use `<form action="...">`.** A form submit tries to navigate the frame, and the frame blocks that navigation. Handle a submit with `@submit.prevent` and Alpine state instead.
- **Support both themes.** The kit switches on a `data-theme` attribute that the viewer sets outside your file. Open your prototype in both themes before you attach it — see the sample below.
- **Label every control.** Give every input, select, and checkbox a `<label for="...">`. Give an icon-only button an `aria-label`. `bridge.js` reports each control by its label. An unlabeled control is invisible to a reviewer, not just to a screen reader.
- **Keep every control reachable by keyboard.** Use real `<button>`, `<input>`, and `<select>` elements. A clickable `<div>` cannot receive keyboard focus.
- **Hold your state in `x-data`.** Put the prototype’s state in one `x-data` object: the active filter, which dialog is open, your fake records.
- **Mark your state’s root element `data-proto-state`.** Add the attribute to the element carrying `x-data`. `bridge.js` reads that element’s Alpine data and reports it to the task page.
- **Use no external images.** Draw an icon as inline SVG, or encode a small image as a `data:` URI. The frame cannot reach an image host.

## The sample prototype

`app/preview/samples/task-board.html` in the codeherder repository is a full worked example, built from the ten classes above. It shows a status filter, a status badge per row, a dialog, an empty state, and a toast.

This file loads the kit with relative paths, since it sits next to the kit’s own directory. Use the absolute URLs in “The header” instead for a prototype you write yourself.

## Related guides

- [Attaching files and images](https://codeherder.com/docs/attachments/) — how to attach a finished prototype to a task with `ch task attachments create <taskId> <file> --prototype`
- [Which model your agents run](https://codeherder.com/docs/agent-models/) — how a workflow stage picks the model an agent runs its session on
