create-component
Create new Prototyper UI components from scratch, including Base UI primitives, registry entries, examples, and MDX documentation.
Install
npx skills add https://github.com/PrototyperAI/prototyper-ui --skill create-component- tools
- [Read, Glob, Grep, Write, Edit, Bash]
Prototyper UI — Creating Components
End-to-end guide for building new components in the Prototyper UI library. Templates first, then decision trees, then architecture patterns, then registration and documentation.
1. Copy-Paste Templates
These four templates cover every component shape. Pick one, fill in the blanks.
Template A: Simple Component (no sub-components)
Used by: Button, Toggle
Template B: Compound Visual Component (Root + sub-components sharing context)
Used by: Switch, Slider, Meter, Progress
Template C: Positioned Overlay (Portal → Positioner → Popup)
Used by: Popover, Tooltip, Menu, Select, Combobox
Template D: Dialog / Full-Screen Overlay (with backdrop)
Used by: Dialog, AlertDialog
2. Component Type Decision Tree
When to use which Base UI primitive
3. Step-by-Step Workflow
Phase 1: Research
- Check Base UI docs — Does a primitive exist? What sub-parts does it expose?
- Check existing Prototyper UI components — Is there a similar component to reference?
- Identify the template — Use the decision tree above to pick A, B, C, or D.
Phase 2: Implement
- Create component file at
apps/docs/registry/ui/{component-name}.tsx - Follow the file header pattern strictly:
- Implement each sub-component — one function per sub-component, not classes.
- Add data-slot to every rendered element.
- Add animation classes — invoke
/animate-uiskill for exact patterns. - Export all components and variants — named exports only, single export block at end.
Phase 3: Register
- Add registry entry to
apps/docs/registry/registry.ts - Create example files in
apps/docs/registry/example/{component-name}/ - Run
pnpm registry:buildto generate JSON +__registry__.tsx
Phase 4: Document
- Create MDX page at
apps/docs/content/docs/components/{component-name}.mdx - Run
pnpm devand verify visually atlocalhost:3333
4. Base UI Wrapping Patterns
Import Convention
Always use deep path imports with an alias:
Accessing Sub-Parts
Base UI exposes sub-parts as properties on the namespace:
Accessing TypeScript Types
Props and state types live on the sub-part namespace:
The render= Prop (NOT asChild)
Base UI uses render= instead of Radix's asChild. Pass a JSX element — Base UI merges all props (handlers, ARIA, refs) onto it:
When render= is passed to Button, set nativeButton={false} to avoid rendering a <button> inside another element:
Data Attributes (NOT data-state)
Base UI uses boolean data attributes, not Radix-style data-state="open":
In Tailwind, target these with data-open:, data-closed:, data-checked:, etc.
Overlay Internal Architecture
Every positioned overlay follows the same three-layer structure internally:
The Content wrapper you expose to users hides this:
Users write <PopoverContent side="top"> — they never see Portal/Positioner/Popup.
5. Props & TypeScript Patterns
Props Type Decision Tree
Props Destructuring Order
Always destructure in this order:
Default Values
Set defaults in the destructuring, not in defaultVariants logic:
No forwardRef
Base UI handles ref forwarding internally. Never use React.forwardRef:
6. Styling Patterns
className Merge Order
Always follow this order in cn():
Standard Base Classes
Every interactive element should include these base utilities:
SVG Icon Normalization
Add to any component that may contain inline SVG icons:
This ensures icons default to size-4 (unless explicitly sized), can't capture pointer events, and don't shrink in flex layouts.
State Transition Classes
The standard state transition string (for color/background/border changes):
Never use transition-all. Enumerate exactly which properties transition.
Token Usage
Always use hover-only:hover: (never bare hover:) and motion-safe:active: (never bare active:scale-*).
Dark Mode
Never use dark: utility classes. Token values swap automatically via .dark class on <html>. If you need dark-mode-only behavior, use the token system in globals.css.
7. Context Pattern
When to Use Context
Context Implementation Pattern
Rules:
- Context always has a default value (never
undefined) - Use
React.createContextat module scope (not inside a function) - Use
React.useContextin sub-components (notuseContextfrom Root) - Name format:
{ComponentName}Ctx(short, clear) - Value type format:
{ComponentName}ContextValue
8. data-slot Convention
Naming Rules
What Gets a data-slot
9. Registry & Examples
Registry Entry
Add to apps/docs/registry/registry.ts:
Category rules:
Dependencies — when to include:
registryDependencies — reference other registry items by name:
Example Files
Location: apps/docs/registry/example/{component-name}/{example-name}.tsx
Naming convention:
{component-name}-demo.tsx— Primary demo (required){component-name}-{variant}.tsx— Variant demos{component-name}-with-{feature}.tsx— Feature showcase
Structure:
Rules:
- Always
export default function(the registry requires default exports) - Import from
@/registry/ui/(not@/components/ui/) - Keep examples minimal — demonstrate one concept each
- Use other Prototyper UI components in examples (Button for triggers, Field for form wrapping)
Build
Generates:
public/r/{name}.json— shadcn-compatible install payloadpublic/r/index.json— registry indexregistry/__registry__.tsx— lazy-loaded example index
10. MDX Documentation Page
Location: apps/docs/content/docs/components/{component-name}.mdx
Template
Examples
Variant Name
Styling
Data Slots
API Reference
<TypeTable type={{ variant: { description: "Visual style of the component", type: '"default" | "outline"', default: '"default"', }, }} />
Accessibility
Keyboard interactions, ARIA attributes, screen reader behavior.
Related
```11. Checklist
Run through this before considering a component complete.
Structure
-
"use client"is line 1 - Imports follow order:
@base-ui/react→ CVA → icons →cn→ local - Deep path Base UI import with alias (
as ComponentNamePrimitive) - Named exports only (no
export default) - Single
export { }block at end of file
Every Element
-
data-slotattribute on every rendered DOM element -
classNameprop accepted and merged viacn()(user class last) - No
React.forwardRef— Base UI handles refs
Interactivity
-
focus-visible:focus-ringon buttons/toggles/triggers -
focus-within:focus-field-ringon form input wrappers -
disabled:status-disabledon disableable elements -
no-highlighton all interactive elements -
hover-only:hover:prefix on all hover states (never barehover:) -
motion-safe:active:scale-[0.97]for press feedback (never bareactive:)
Animation
-
motion-reduce:transition-nonealongside everytransition-* -
motion-reduce:animate-nonealongside everyanimate-in/animate-out - Overlay animations follow the exact patterns from
/animate-uiskill -
origin-(--transform-origin)on all positioned overlay popups -
data-entering:will-change-[...]/data-exiting:will-change-[...]on animated overlays - Exit animations faster than enter (100ms exit vs 150ms enter)
Tokens
- Using semantic tokens (
bg-primary,shadow-overlay) not raw colors - No
dark:classes — token swap handles dark mode - No
transition-all— properties explicitly enumerated - No bare
shadow-lg/shadow-md— useshadow-surface/shadow-field/shadow-overlay
Registry
- Entry added to
registry/registry.tswith correct dependencies - Example created at
registry/example/{name}/{name}-demo.tsx -
pnpm registry:buildruns without errors - MDX page created at
content/docs/components/{name}.mdx - Component renders correctly in dev server
TypeScript
- Props type uses
&intersection (Primitive.Props & VariantProps & custom) - Overlay Content uses
Pick<Positioner.Props, ...>for positioning - Default values in destructuring, not in function body
- No type assertions (
as) unless absolutely necessary
12. Common Mistakes
13. Cross-References
- No Base UI primitive exists: Invoke
/build-primitivefor ARIA contracts, keyboard navigation, focus management, controlled/uncontrolled state, form integration — building from scratch - Animation details: Invoke
/animate-uifor exact easing, duration, and per-component overlay classes - Component API reference: Invoke
/prototyper-uifor design tokens, component selection, and copy-paste usage patterns - Base UI primitives:
https://base-ui.com/react/components/{name}for primitive API docs