skills/keystoneui-react/SKILL.md
Manages Keystone UI components and projects — adding, searching, fixing, debugging, styling, and composing UI built on Tailwind CSS v4 + Base UI. Provides project context, component docs, and usage examples. Applies when working with Keystone UI, @keystoneui/react, components.json with @keystoneui/* registries, or any project with @keystoneui/react in its dependencies. Also triggers for "keystoneui add", "find a Keystone UI example", or "switch to Keystone UI".
npx skillsauth add keystone-ui/react keystoneui-reactInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A production-ready React component library built on Tailwind CSS v4 and Base UI (@base-ui/react), with 50+ accessible components, OKLCH semantic tokens, and dark mode.
@keystoneui/react/button, never @keystoneui/react. There is no barrel.@base-ui/react. The slot pattern is render, not asChild. → rules/base-vs-radix.mdbg-primary, text-muted-foreground, never raw colors.data-slot is the public API — every part has a stable data-slot for styling targets.Two paths reach the same library — pick one. See cli.md for both.
# As an npm dependency
pnpm add @keystoneui/react
# Or vendor source via shadcn-compatible registry
npx shadcn@latest add https://keystoneui.io/r/button.json
CSS setup (order matters):
@import "tailwindcss";
@import "@keystoneui/react/base.css";
Then define theme tokens — see customization.md.
These are always enforced. Each links to a file with code pairs.
bg-primary, text-muted-foreground — never raw Tailwind colors.<Button variant="outline">, not className="border ...".className for layout, not styling. Don't override component colors or typography.space-x-* / space-y-*. Use flex + gap-*.size-* when width and height are equal. size-10, not w-10 h-10.transition-all. Specify exact properties. (Button is the documented exception.)[&>a]:hover:bg-muted, not [&>a:hover]:bg-muted — the second form bypasses @media (hover: hover).z-index on overlay components. Use the --z-* scale; library components manage stacking.disabled: and data-disabled:. Always include cursor-not-allowed and opacity-50.Form/Label/Description/ErrorMessage from /form. Rich: Field/FieldLabel/FieldDescription/FieldError from /field. Pick one per form.<Form> renders a <form> element. Use onSubmit directly.InputGroup requires InputGroupInput/InputGroupTextarea. Never raw Input inside InputGroup.InputGroupAddon (and optionally InputGroupButton).ToggleGroup. Don't loop Button with manual active state.FieldSet + FieldLegend for grouped checkboxes/radios. FieldLegend accepts variant="label" for inline forms.aria-invalid on the control + FieldError (or ErrorMessage). Don't use data-invalid on Field — it doesn't style anything in Keystone UI.disabled on the control; optionally data-disabled on Field to dim the FieldLabel via the group/field selector.render, not asChild. Base UI's slot pattern.SelectItem → SelectContent, TabsTrigger → TabsList, DropdownMenuItem → DropdownMenuContent.Modal, Drawer, AlertDialog need a title. Use className="sr-only" to hide it visually.CardHeader/CardTitle/CardDescription/CardContent/CardFooter.Button has no isLoading prop. Compose with Spinner + disabled.data-slot is stable. Use it for consumer overrides; don't override slot values when extending.lucide-react for all icons. No @iconify/react, @remixicon/react (in app code), or other libraries.icon={Check}, not icon="check".@radix-ui/*. Use Keystone UI's wrappers, which use @base-ui/react.render instead of asChild. <ModalTrigger render={<Button />}>Open</ModalTrigger>.data-open / data-closed / data-checked instead of Radix-style data-state="open".// Subpath import — every part comes from the same path
import { Modal, ModalTrigger, ModalContent, ModalTitle } from "@keystoneui/react/modal";
// Form: Form (real <form>) + FieldGroup + Field, controls inside Field
// Form from "/form"; Field & friends from "/field"
<Form onSubmit={handleSubmit}>
<FieldGroup>
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" name="email" type="email" />
</Field>
</FieldGroup>
<Button type="submit">Sign in</Button>
</Form>
// Validation: aria-invalid on the control + FieldError for the message
<Field>
<FieldLabel>Email</FieldLabel>
<Input aria-invalid />
<FieldError>Invalid email.</FieldError>
</Field>
// Custom trigger: render prop, not asChild
<ModalTrigger render={<Button variant="secondary" />}>Open</ModalTrigger>
// Spacing: gap, not space-y
<div className="flex flex-col gap-4">...</div>
// Status: Badge or semantic tokens, not raw colors
<Badge variant="secondary">+20.1%</Badge>
// Loading: compose, no isLoading prop
<Button disabled={isPending}>
{isPending && <Spinner />}
{isPending ? "Saving..." : "Save"}
</Button>
| Need | Use |
|---|---|
| Action / button | Button (variants: default, secondary, outline, ghost, destructive, link) |
| Form layout | Form + FieldGroup + Field |
| Text input | Input, Textarea, InputGroup (with addons), InputOTP |
| Choice (one of many) | Select, Combobox (searchable), RadioGroup, NativeSelect |
| Choice (toggle) | ToggleGroup (2–5 options), Switch (boolean), Checkbox |
| Date / time | DateInput, Calendar |
| Overlays | Modal, Drawer, AlertDialog, Popover, Tooltip |
| Menus | DropdownMenu, Command (palette) |
| Navigation | Tabs, Breadcrumb, Pagination, Stepper |
| Data display | Table, Card, DescriptionList, Avatar, Badge, Tag, TagGroup |
| Feedback | Toast, Alert, Progress, CircularProgress, Skeleton, Spinner, Empty |
| Layout | Card, Separator, Resizable, Accordion, Collapsible, AspectRatio, Carousel |
| Bulk-action bar | SelectionBar |
Blocks are full-page or feature-level compositions, not primitives. If the user asks for a complete page or feature, check blocks before composing from primitives — installing a block is faster and yields a more cohesive result.
| User asks for… | Block(s) to consider | Category |
|---|---|---|
| Sign-in form / login page | signin-01, signin-02, signin-03, signin-04 | authentication, login |
| Signup / registration page | signup-01, signup-02, signup-03, signup-04, signup-05 | authentication, signup |
| Profile dropdown / user menu | profile-dropdown-01 | navigation |
| Tickets / CRM / data management table | tickets-01 | data |
| Betting panel / wager UI | betting-panel-01, betting-panel-02, betting-panel-03, betting-panel-04 | betting |
Install a block: npx shadcn@latest add https://keystoneui.io/r/<name>.json. Or via the unified CLI: keystoneui blocks to list, keystoneui blocks --category authentication to filter, keystoneui blocks <name> to view source. The --category flag works on list and search too.
54 components, all importable from @keystoneui/react/{kebab-case-name}:
accordion, alert, alert-dialog, aspect-ratio, avatar, badge, breadcrumb, button, button-group, calendar, card, carousel, checkbox, circular-progress, collapsible, combobox, command, date-input, description-list, drawer, dropdown-menu, empty, field, form, input, input-group, input-otp, item, kbd, label, modal, native-select, pagination, popover, progress, radio-group, resizable, select, selection-bar, separator, skeleton, slider, spinner, stepper, switch, table, tabs, tag, tag-group, textarea, toast, toggle, toggle-group, tooltip.
search_components / list_components, the keystoneui search/keystoneui list CLI verbs, or node scripts/list_components.mjs.apps/docs/demos/<component>/<variant>.tsx directly. These are real, working compositions authored by the team — examples include apps/docs/demos/table/with-pagination.tsx, apps/docs/demos/card/with-image.tsx. Via MCP, the equivalent is get_examples({ name: "<component>" }) which returns all demos for the component as a bundle.apps/docs/demos/blocks/<name>.tsx and the docs at apps/docs/content/docs/blocks/<name>.mdx. Existing categories: Sign in (signin-01..04), Signup (signup-01..05), User (profile-dropdown-01), CRM (tickets-01), Betting (betting-panel-01..04). Via MCP, use list_components({ type: "block" }) or search_components({ query: "...", type: "block" }). Always try a block before composing a page from primitives.view_component (MCP), node scripts/get_component_docs.mjs <name>, or fetch https://keystoneui.io/llms.mdx/docs/components/<name> directly (the /llms.mdx/... route returns MDX with <ComponentPreview> tags resolved to inline TSX source — single round-trip). Always read the docs before implementing complex components.npx shadcn@latest add <url> (vendored source) or pnpm add @keystoneui/react (npm dependency). See cli.md.audit_checklist after first install to catch missing CSS imports or tokens.Before reaching for the docs site, these directories in the repo are authoritative:
apps/docs/demos/<component>/ — per-component example variants (e.g., table/with-pagination.tsx, card/with-image.tsx). Resolved by <ComponentPreview name="<component>-<variant>" /> tags in MDX.apps/docs/demos/blocks/ — full-page block compositions (signin-01.tsx, tickets-01.tsx, profile-dropdown-01.tsx, …).apps/docs/content/docs/components/ — per-component MDX docs.apps/docs/content/docs/blocks/ — per-block MDX docs with install commands and components-used cross-links.packages/ui/src/ — the component source. Read for prop semantics; consult demos for usage patterns.For LLM-friendly fetched content, use:
https://keystoneui.io/llms.mdx/docs/components/<name> — per-component MDX with <ComponentPreview> resolved inline as tsx blocks.https://keystoneui.io/llms.mdx/docs/blocks/<name> — same for blocks.https://keystoneui.io/llms-components.txt — every component in a single document.npx shadcn@latest add, npm package install, bundled scripts, direct MDX URLsForm, FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validationrender, compound parts, group items, Modal title, Card composition, data-slotrender vs asChild, attribute semantics, animation attributesdevelopment
--- name: web-animation-design description: Design and implement web animations that feel natural and purposeful. Use this skill proactively whenever the user asks questions about animations, motion, easing, timing, duration, springs, transitions, or animation performance. This includes questions about how to animate specific UI elements, which easing to use, animation best practices, or accessibility considerations for motion. Triggers on: easing, ease-out, ease-in, ease-in-out, cubic-bezier, b
development
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
development
Use this agent to create or update technical documentation for Keystone UI components, features, or guides. This includes Storybook stories in /apps/storybook/stories/ and (future) Fumadocs MDX documentation. The agent follows Keystone UI's documentation standards emphasizing brevity, accuracy, and practical code examples. Triggers on keywords like write documentation, create story, new component docs, write stories, document component, add storybook story, update docs, create guide.
development
Use this agent to review, improve, or curate documentation files for Keystone UI. This includes Storybook stories in /apps/storybook/stories/ and (future) MDX documentation. The agent verifies accuracy against component source, ensures completeness of variant/state coverage, improves code examples, and maintains consistency with Keystone UI patterns. Triggers on keywords like review stories, improve documentation, curate docs, audit stories, check documentation quality, story review, docs review.