# Introduction

_Box Kite 2.2.2 · a markdown copy of https://www.box-kite.dev/_

[Version 2.2.2](https://www.box-kite.dev/releases.md)

# The React library your AI already knows. Every CSS property is a typed prop.

The instructions an agent needs ship inside the package, generated from the engine itself. 235 props the compiler checks catch what it still gets wrong. 38 components arrive with the keyboard and the ARIA already in them. No stylesheet, no build step, no `'use client'`.

p={4} · padding: 1rem · spacing is ÷4

fontSize={14} · font-size: 0.875rem · type is ÷16, so the number is the pixel size

borderRadius={4} · border-radius: 1rem · the spacing scale again

b={4} · border-width: 4px · a border is measured in pixels

lineHeight={24} · line-height: 24px · so is a line box

bgColor="sky-500" · background-color: var(--sky-500,oklch(68.5% .169 237.3)) · a token, so a theme can move it

The same `4` is a rem here and a pixel there, because a padding and a border are not measured the same way. The editor knows which is which, and so does anything reading the same types.

### An agent writes it correctly

The rules, every prop with the CSS it emits, and an MCP server that runs the real engine all ship inside the package — generated from the prop registry, so what a model reads is never a version behind what it is writing against.

What is in the tarball

### And the compiler catches the rest

235 CSS properties the compiler checks, so a value a model invented is an error in your editor rather than an element that renders with no background.

A real compiler diagnostic

### A model can compose the UI at runtime

catalog() describes every component and every value its props take as JSON Schema, and <SpecRenderer> renders what comes back against the components your app allows — an unknown name renders nothing.

The schema, and what it refuses

### What it writes is finished

Ten components implement a published W3C pattern with the keyboard tested on every commit, every one of them renders in a Server Component, and the data grid is in the box.

The pattern table, generated

## The instructions are inside the package

A model writing against a library it has not seen guesses, and a guess that compiles is the expensive kind. So the answers travel with the code: installing `@box-kite/react` installs the rules, the whole prop reference and a docs folder beside them. Every file is generated at build time from the prop registry, the component types or the rules file — a stale instruction file is worse than none, because an agent trusts it over its priors.

| In the package | What it is |
| --- | --- |
| `AGENTS.md` | The rules, and the block that tells a model its prior is a different library. Read first. |
| `docs/props.md` | Every prop, the values it takes and one example measured from the engine. |
| `docs/components.md` | Every component, its import specifier and whether it renders on a server — read off the built chunks' own exports. |
| `docs/a11y.md` | The behaviour hooks, for a pattern this library does not ship. |
| `docs/anchor.md` | Where a floating layer goes, in CSS and in the measured fallback. |
| `docs/catalog.md` | What a generated UI may build, and how it renders. |
| `docs/interop.md` | The agentic runtimes, each verified against its own published package. |
| `docs/mcp.md` | The MCP server, and why one tool of it cannot be replaced by a file. |
| `BOX_KITE_AI_CONTEXT.md` | The long-form reference: prop tables, the DataGrid API, debugging. |
| `.claude/skills/box-kite/` | The same rules as an installable skill, with four references beside it. |
| `.cursor/rules/box-kite.mdc` | That skill as a Cursor rule. |

### One line, whichever agent you use

**Any agent that reads a root AGENTS.md**

```shell
cp node_modules/@box-kite/react/AGENTS.md ./AGENTS.md
```

**As a skill, in roughly forty-five agents**

```shell
npx skills add box-kite/box-kite
```

**As an MCP server, with the engine behind it**

```shell
npx @box-kite/mcp
```

### The answer a file cannot give

A value this library does not accept writes no CSS and says nothing about having done so — so the one question a reference cannot settle is “did that actually work?”. `@box-kite/mcp` answers it by running the engine: hand `check_styles` a prop bag and it reports the CSS each prop wrote, or why it wrote none. Six tools over stdio, with the engine and the generated reference inlined.

| Tool | What it answers |
| --- | --- |
| `search_docs` | The prop, component, nesting key or rule for what you are building — ranked across all four. |
| `get_props` | A prop's whole record, with a numeric prop's scale measured at 1/2/4/8 rather than described. |
| `get_component` | One component's contract: props and defaults, sub-parts, the keyboard map and the ARIA it writes. |
| `get_rules` | The rules the library is written by, as an index or in full. |
| `get_blocks` | Whole sections the shadcn CLI installs — a data-grid page, a settings form, a dashboard shell. |
| `check_styles` | A prop bag through the real engine: the CSS each prop wrote, or why it wrote none. |

- **Generated, not written.** Every example in `docs/props.md` is the CSS the engine emitted for it, and CI fails when one drifts — so the reference cannot describe a divider the library no longer uses.
- **The prior is the problem, and it is addressed first.** The prop names collide with other libraries’ while the numbers mean different things, so `AGENTS.md` opens by saying so rather than assuming a model arrives empty-handed.
- **The site is readable too.** Every page here has a markdown mirror, and `llms.txt` indexes them — so an agent browsing the docs gets prose rather than a React shell.

[Set your agent up, step by step](https://www.box-kite.dev/ai-context.md) · [Every prop, with the CSS it writes](https://www.box-kite.dev/box.md)

## A value the palette does not have is an error

Generated code is only as good as what catches it. Both columns below make the same mistake — the one a model makes most, a plausible value from a neighbouring scale, since no palette family has a `550` step. Only one of them says so.

**A class name**

`<div className="rounded-lg bg-blue-550 p-4">`

No error anywhere — not in the editor, not in the build, not at runtime. The element renders with no background, and whoever asked for it finds out by looking.

**A typed prop**

`<Box bgColor="blue-550" borderRadius={2} p={4} />`

`error TS2820: Type '"blue-550"' is not assignable to type (every colour token in the palette). Did you mean '"blue-50"'?`

The compiler's own message, in the editor, before it is ever run. This site's test suite re-runs it rather than trusting what is printed here.

- **It suggests the fix.** The diagnostic ends in `Did you mean "blue-50"?` — which is a repair an agent can apply on its own, from a message no string could have produced.
- **Nothing merges.** Two components setting the same prop resolve by prop, last one wins — so there is no class-string arithmetic and no specificity to hold in your head.
- **The class is shared.** `p={4}` is one rule however many components write it, generated the first time it is used and reused after that.
- **The 5% has a door.** A property with no prop goes in `css={{ … }}`, which still compiles to a shared class — never a `style` attribute.

[Every prop, with the CSS it writes](https://www.box-kite.dev/box.md) · [The one-off that is still a class](https://www.box-kite.dev/escape-hatch.md)

## A model composes it, your app still owns it

The other half of writing code with a model is letting one build the interface at runtime. `catalog()` describes every component and every value its props take as JSON Schema — read off the live prop registry, so a prop you added with `Box.extend()` is in it with nothing regenerated. `specSchema()` turns that into the one schema a model generates a whole tree under, and `<SpecRenderer>` renders what came back against an allow-list your app builds.

**The constraint and the renderer come out of one description**

```jsx
import { catalog, specSchema } from '@box-kite/react/catalog';
import { SpecRenderer, createSpecRegistry } from '@box-kite/react/spec';

const registry = createSpecRegistry({ catalog: catalog(), components: { Flex, H2, Sparkline } });

// On the server: what the model is allowed to generate.
const schema = specSchema(registry);

// In the app: what came back, rendered against the same description.
<SpecRenderer spec={spec} registry={registry} data={data} onAction={run} onIssues={log} />;
```

- **A colour stays a token.** A colour prop is a pattern over the palette in the schema, which is the one thing a generated tree cannot get around — so a model cannot invent a brand colour into your app.
- **Unknown names render nothing.** A component the registry does not hold, a prop its schema refuses, an event the catalog does not list: each is dropped and reported through `onIssues` rather than thrown or silently obeyed.
- **A stream is handled as a stream.** A spec arrives in pieces, so a half-written value is held back rather than rendered, and every node has an error boundary of its own — a component that throws on invented props costs that node and nothing around it.
- **The runtimes are already mapped.** `@box-kite/react/interop` reads a tool call from AI SDK, assistant-ui, CopilotKit, AG-UI and A2UI into one vocabulary — and imports none of them, so the adapter does not choose a runtime for your app.

[The catalog and the renderer](https://www.box-kite.dev/generative-ui.md) · [Five runtimes, one vocabulary](https://www.box-kite.dev/interop.md) · [The components an agent’s turn needs](https://www.box-kite.dev/agent.md)

## What comes out is finished, not scaffolding

Code a model wrote is worth what it does for the person using it. Every pre-built component ships with its roles, its ARIA and its keyboard map, and the two numbers beside each one come out of the generated reference: how many keyboard rows that component documents, and how many fixtures the axe sweep renders it in.

| Component | W3C pattern | Keyboard rows | Axe fixtures |
| --- | --- | --- | --- |
| [Dropdown](https://www.box-kite.dev/dropdown.md) | [combobox](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/) | 18 | 3 |
| [DataGrid](https://www.box-kite.dev/datagrid.md) | [grid](https://www.w3.org/WAI/ARIA/apg/patterns/grid/) | 16 | 6 |
| [Menu](https://www.box-kite.dev/menu.md) | [menu-button](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/) | 7 | 1 |
| [Tooltip](https://www.box-kite.dev/tooltip.md) | [tooltip](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/) | 6 | 2 |
| [Slider](https://www.box-kite.dev/slider.md) | [slider](https://www.w3.org/WAI/ARIA/apg/patterns/slider/) | 5 | 1 |
| [Tabs](https://www.box-kite.dev/tabs.md) | [tabs](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) | 5 | 3 |
| [Accordion](https://www.box-kite.dev/accordion.md) | [accordion](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/) | 4 | 1 |
| [RadioGroup](https://www.box-kite.dev/radiobutton.md) | [radio](https://www.w3.org/WAI/ARIA/apg/patterns/radio/) | 4 | 1 |
| [Switch](https://www.box-kite.dev/switch.md) | [switch](https://www.w3.org/WAI/ARIA/apg/patterns/switch/) | 3 | 1 |
| [Checkbox](https://www.box-kite.dev/checkbox.md) | [checkbox](https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/) | 2 | 2 |

105 · keyboard rows documented and driven, across every component

51 · axe fixtures rendered on every commit, over 38 components

0 · violations in the ledger, which fails on a listed one that stops firing too

### It renders in a Server Component, with nothing added

A Server Component cannot inject styles: there is no effect to run and no document to write to. The `react-server` condition resolves to a build of Box that calls no hook and touches no DOM, and the rules it needs come back as `<style href precedence>` elements React 19 hoists and dedupes. Importing the package is the whole setup — which is also why generated code needs no `'use client'` added to it after the fact.

**app/page.tsx — no 'use client', no provider, no stylesheet**

```jsx
import Flex from '@box-kite/react/components/flex';
import { H1, P } from '@box-kite/react/components/semantics';

export default function Page() {
  return (
    <Flex d="column" gap={2} p={6} borderRadius={2} bgColor="slate-50" theme={{ dark: { bgColor: 'slate-900' } }}>
      <H1 fontSize={24} fontWeight={600}>Rendered on the server</H1>
      <P color="slate-600" hover={{ color: 'sky-500' }}>Pseudo-classes, breakpoints and themes are just more rules.</P>
    </Flex>
  );
}
```

- **The boundary is a check, not a promise.** CI fails if the `react-server` entry reaches a client hook, or if the engine itself imports React.
- **The class names match.** They are content hashes, so the class the server resolved is the class the browser bundle resolves — there is no hydration mismatch to configure away.
- **This site is the proof.** Every page here is prerendered in Node through the library’s own `getStyles()`, and a Next.js App Router example is built and smoke-tested on every commit.

### And the data grid is in the box

Sorting, multi-column grouping with aggregation, row virtualization over 100,000 rows, tree data, a server-side row model, range selection with clipboard paste, cell editing and a styled XLSX export. MIT, one tier, in the same package as everything else, taking Box props like everything else — so a grid a model generated is the grid you would have written.

[The grid, with every feature demoed](https://www.box-kite.dev/datagrid.md) · [The 100,000-row benchmark](https://www.box-kite.dev/benchmark.md) · [How the server path works](https://www.box-kite.dev/server-components.md)

## Two dependencies and no configuration

There is no plugin to register, no content globs to keep in step and nothing to import into your entry file.

**1. Install**

```shell
npm install @box-kite/react
```

**2. There is no step two**

```jsx
import Box from '@box-kite/react';

export default function App() {
  return (
    <Box p={4} bgColor="indigo-500" color="white" borderRadius={2}>
      Hello, Box Kite!
    </Box>
  );
}
```

New to web development? Build a whole page step by step in [Your first web page with Box Kite](https://www.box-kite.dev/blog/start-building-with-box-kite.md).

Licence · MIT · Every component, every version. There is no tier above this one.

Latest · 2.2.2 · Semver, with a written note for every change a consumer sees.

Runtime dependencies · 0 · React and React DOM are peers; nothing else ships.

Peer range · React 18 & 19 · Both run the whole suite on every commit.

[Releases, every version](https://www.box-kite.dev/releases.md)[What an agent should read](https://www.box-kite.dev/ai-context.md)[The package](https://www.npmjs.com/package/@box-kite/react)

---

_Every page: https://www.box-kite.dev/llms.txt · every prop, measured: https://www.box-kite.dev/props.md_

