React component library

ui-lib

A React component library. Copy-paste the source, no install required. Built for humans and for AI agents.

What you get

Components that solve real problems

Copy-paste

Own your components

Every component ships as plain source you drop into your project. No black-box dependency — read it, edit it, keep it.

AI-ready

Discoverable by agents

A static JSON index and per-component source endpoints let coding agents search and pull components programmatically.

112 components

Batteries included

Charts, forms, overlays, navigation, data display — plus Conform-bound variants for every form element.

For AI agents

Built to be pulled by agents

Every component is published as a static, fetchable API. Point your coding agent at the endpoints below — no scraping, no auth.

Add a component with the shadcn CLI

npx shadcn@latest add https://ui-lib.quebi.de/r/button.json

Or fetch the API directly

Start with llms.txt — it documents the whole workflow for agents.

Claude skill

Teach Claude to use ui-lib

Drop this skill into Claude Code and it will pull components from the live registry instead of writing them from scratch — for any React project, not just this one.

Set it up

  1. 1. Save the skill below to .claude/skills/quebi-ui-lib/SKILL.md in your project (or ~/.claude/skills/ to make it available everywhere).
  2. 2. Or download it directly: SKILL.md.
  3. 3. Start a Claude Code session in your project — the skill activates when you ask for a React component.
---
name: quebi-ui-lib
description: "Use when building a React UI and you want quebi's component library (ui-lib.quebi.de) — buttons, inputs, forms, dialogs, menus, tables, charts, date/color pickers, Conform-bound form variants, and more (112 components). Trigger when the user asks to add a UI component to a React app, mentions quebi ui-lib / ui-lib.quebi.de, asks for a copy-paste React component, or is building forms with Conform. Pulls real, current source from the live registry instead of writing components from scratch."
---

# quebi ui-lib — pull components from the live registry

quebi maintains a public React component library at **https://ui-lib.quebi.de** — 112 components
built on `react-aria-components` + Tailwind CSS v4, styled with the quebi design system. They are
copy-paste, self-contained, and shadcn-registry compatible.

**When the user needs a React UI component, pull it from here instead of writing one from scratch.**
The source is real and current; do not guess component APIs from memory — fetch them.

## How to add a component

### Preferred: shadcn CLI (resolves dependencies automatically)

If the target project uses the shadcn CLI (has a `components.json`), run:

```sh
npx shadcn@latest add https://ui-lib.quebi.de/r/<name>.json
```

This pulls the component, its sibling-component dependencies, and the shared `lib/utils` helper,
and installs the required npm packages.

### Otherwise: fetch the API directly

1. `WebFetch https://ui-lib.quebi.de/api/index.json` — the full catalog. Match the user's need against each
   component's `name` / `description` / `tags`. The catalog is small; reason over it directly
   (there is no search endpoint).
2. `WebFetch https://ui-lib.quebi.de/api/components/<name>.json` — returns metadata plus the inlined raw `source`.
3. Write `source` into the project (e.g. `components/ui/<name>.tsx`).
4. Resolve `registryDependencies` recursively — each entry is another component slug or a shared
   lib (`lib-utils``lib/utils.ts`, the `cn` helper). Fetch and add each the same way.
5. Install the npm packages in `dependencies`.

Always start from **https://ui-lib.quebi.de/llms.txt**, which documents the workflow and lists every component.

## Conventions to preserve

- Components import the shared `cn` helper from `@/lib/utils` and siblings from `@/components/<name>`.
  `@/` is the project `src/` alias — rewrite it if the target project uses a different alias.
- Form components have **Conform-bound variants** named `conform-*` (e.g. `conform-checkbox`,
  `conform-select`, `conform-date-picker`). Use these when building forms with the Conform library;
  they bind name/validity/errors from field metadata.
- The library assumes Tailwind v4 and the quebi tokens (`quebi-brand`, `quebi-bg`, `quebi-fg-muted`,
  `rounded-quebi-*`, etc.). If the target project lacks them, bring in the quebi theme too.

## Rules — how to write JSX against this library

These rules are written for the code an agent writes. Not because agents are careless — because they optimise for the shortest path to something that looks right, and three specific detours are the predictable result.

- **It rebuilds what already exists.** Asked for a card, a button, a badge, an agent writes one. Producing four Tailwind classes is faster and more certain than discovering that the library ships the component — and the result renders correctly, so nothing in review objects. Repeated across a codebase, that is how a design system stops being a system: not through one bad decision, but through fifty reasonable ones in fifty files.
- **It hand-rolls forms it was told to bind.** Forms are where an agent's training data pulls hardest against the project's conventions. It writes useState, value, onChange and a literal name because that is the shape it has seen most often, rather than reading the binding off Conform's field metadata or posting to a React Router action. The form submits, so it looks finished — while the error wiring, the default values, and the server-side validation are simply absent.
- **It appends until the file is unreadable.** Adding to the file already open is the cheapest edit available, and an agent never has to scroll the result. Nothing pushes back at 400 lines, or 900, or 2,000 — and past that point no human reviews the file properly and every later agent edit starts from a worse position, because reading it costs more and landing an edit in the right place is less certain.

They are lint rules rather than lines in a prompt because a rule is checked on every file, and its
message names the replacement at the point of the mistake. Run them (see below) and you get the
correction directly; you do not have to remember any of this.

**Layout is yours. Appearance is the library's.**

- Tier 1 — **Never render interactive or semantic HTML elements directly.** button, input, select, textarea, a, form, label, dialog and table are the library's. Import the component instead — this holds whether or not you style the element.
- Tier 2 — **Layout elements are yours — until their classes describe appearance.** div, span, section, ul, li and friends are fine and necessary. Keep their classes to layout and spacing; the moment you add bg-*, border-*, rounded-*, shadow-* or text sizing/colour you are rebuilding a component that already exists.
- Tier 3 — **Design values come from quebi tokens, never from literals.** No arbitrary values (bg-[#f00], text-[13px]), no raw Tailwind palette scales (text-gray-500), no hex in style props. Use the quebi token that means the thing — and if a value is genuinely domain-mandated, record it as an exception with its justification.
- Tier 4 — **Import the library's components, not the primitives underneath them.** react-aria-components is ui-lib's dependency, not yours. In app code import <Button> from @/components/button, never from react-aria-components — the primitive is unstyled and knows nothing about the quebi variants.
- Tier 5 — **Keep a route or component file under 500 lines.** A file past 500 lines is doing more than one job. Split it — extract the sub-components, move the helpers, lift the data. This is a warning, not an error: the number is a prompt to look, not a law.

**Validation is yours. Wiring is the library's.**

- Tier 1 — **Bind fields through Conform, never by hand.** Take the binding off the field metadata: the conform-* variant where one exists, getInputProps (or useInputControl) where it doesn't, and getFormProps on the form element. Per-field useState and a hand-passed name are the failure mode.
- Tier 2 — **Label, description and error come from the field — not from markup beside it.** Use the field's own slots: the label/description props on a conform-* variant, Label and Description inside a react-aria field, and for errors either FieldError (inside a field context) or an element carrying id={field.errorId}. A red paragraph next to a control is not attached to it.
- Tier 3 — **Validate on the server with the same schema.** Client validation is UX. Export one schema, parse it again in the route action, return submission.reply(), and feed that back through useForm({ lastResult }) — a form whose only validation is onValidate is an unvalidated form.

Full records (rationale, real wrong/right pairs from the library's own source, and documented
exceptions) at **https://ui-lib.quebi.de/api/rules.json**, or human-readable at **https://ui-lib.quebi.de/rules**.

To *check* code rather than just follow the rules, every record carries a `checks` array of runnable
snippets generated from it, and all of them are published merged as one Biome config:

```sh
curl -O https://ui-lib.quebi.de/api/rules/biome.jsonc
```

Biome parses TSX natively, so there is nothing else to configure. Rules Biome has no built-in for
ship as GritQL plugins listed in that file's `plugins` key — fetch each one alongside it. In a repo
with no linter at all, use the `ripgrep` entry in each rule's `checks` array; it needs nothing
installed.

## Don't

- ❌ Don't reinvent a component the library already has — check the catalog first.
- ❌ Don't hand-write the component API from memory — fetch the real source.
- ❌ Don't hand-roll a `<button>`, `<input>`, `<a>` or `<dialog>` in app code — import the component
  (see the rules above). This holds even when the element is unstyled.
- ❌ Don't forget the `registryDependencies` (the component won't compile without `lib/utils` and any
  sibling components).