Claude-skill-registry component demo
Create demonstration pages for components and hooks.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/component-demo" ~/.claude/skills/majiayu000-claude-skill-registry-component-demo && rm -rf "$T"
skills/data/component-demo/SKILL.mdComponent Demo Skill
This skill guides the creation and maintenance of components and their demo pages in the Protobox component showcase.
When to Use This Skill
Use this skill when:
- Creating new custom components in
src/components/ - Creating new custom hooks in
src/hooks/ - Updating existing components or hooks
- Planning feature additions that involve reusable components
Component Development Workflow
Phase 1: Planning - Ask About Demo Pages
IMPORTANT: When planning to create a new component or hook, ALWAYS ask the user:
"Would you like me to create a demo page for this [component/hook] in the component showcase?"
Options to present:
- Yes, create demo page - Create both the component and a showcase demo
- Yes, standalone demo - Create component and a standalone demo page at
/[name]-demo - Yes, playground - Create an interactive playground with props controls (Storybook-like)
- No demo needed - Just create the component/hook
Phase 2: Component Creation
Create the component in the appropriate location:
- Custom components:
src/components/[ComponentName].tsx - Custom hooks:
src/hooks/[hookName].tsx - UI components: Use
for shadcn componentsnpx shadcn-ui@latest add [component]
Follow component best practices from
src/components/README.md:
- Simple default usage with sensible defaults
- Accept
,style
, and native element propsclassName - Use composition for icons (via props, not hardcoded)
- Standard heights: 16px, 20px, 40px
- Support dark mode with Tailwind
variantsdark:
Phase 3: Demo Page Creation (if requested)
A. For Component Showcase (/components/[name]
)
/components/[name]-
Create Content Component in
:src/components/DemoShowcase/[Name]Content.tsx- Extract core demo functionality without page wrappers
- Remove:
, full-page padding, headers, back linksmin-h-screen - Keep: interactive elements, controls, examples
- Use Card components to organize examples
- Include usage code examples
-
Register in Demo Registry (
):src/components/DemoShowcase/demoRegistry.tsx// Add lazy import const [Name]Content = lazy(() => import('./[Name]Content')) // Add to DEMO_REGISTRY array { id: '[name]', label: '[Display Name]', section: 'Hooks' | 'Components', component: [Name]Content, description: 'Brief description', path: '/components/[name]', } -
Add Route in
:src/App.tsx// Add lazy import at top const [Name]Content = lazy(() => import('./components/DemoShowcase/[Name]Content')) // Add route inside <Route path="/components"> nested routes <Route path="[name]" element={ <Suspense fallback={<div>Loading...</div>}> <[Name]Content /> </Suspense> } />
B. For Standalone Demo Page (/[name]-demo
)
/[name]-demo-
Create Page Component in
:src/pages/[Name]Demo.tsx- Include full-page wrapper with proper styling
- Add header with title and description
- Organize examples using Card components
- Include code examples showing usage
- Add back link to home
-
Add Route in
:src/App.tsximport [Name]Demo from './pages/[Name]Demo' <Route path="/[name]-demo" Component={[Name]Demo} />
C. For Component Playground (/components/[name]-playground
)
/components/[name]-playgroundPlaygrounds provide an interactive, Storybook-like environment with a canvas and props controls.
-
Analyze Component Props:
- Read the target component's source file
- Parse the TypeScript Props interface
- Categorize props as controllable or complex
-
Guide Prop Selection - Present to User:
"I analyzed [ComponentName] and found these props:
Recommended for playground (controllable):
: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'variant
: 'default' | 'sm' | 'lg' | 'icon'size
: booleandisabled
Complex props (not controllable):
: functiononClick
: boolean (affects render behavior)asChild
: React refref
Which props would you like to expose in the playground?"
-
Create Playground Content in
:src/components/DemoShowcase/[Name]PlaygroundContent.tsximport PlaygroundCanvas, { PropSchema } from './PlaygroundCanvas' import { Button } from '@/components/ui/button' const propSchema: PropSchema = { variant: { type: 'select', options: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'], defaultValue: 'default', }, size: { type: 'select', options: ['default', 'sm', 'lg', 'icon'], defaultValue: 'default', }, disabled: { type: 'boolean', defaultValue: false, }, children: { type: 'string', defaultValue: 'Button', }, } export default function ButtonPlaygroundContent() { return ( <PlaygroundCanvas componentName="Button" propSchema={propSchema} defaultProps={{ children: 'Click Me' }} > {(props) => <Button {...props}>{props.children as string}</Button>} </PlaygroundCanvas> ) } -
Register in Demo Registry (
):src/components/DemoShowcase/demoRegistry.tsx// Add lazy import const [Name]PlaygroundContent = lazy(() => import('./[Name]PlaygroundContent')) // Add to DEMO_REGISTRY array { id: '[name]-playground', label: '[Name] Playground', section: 'Components', component: [Name]PlaygroundContent, description: 'Interactive playground for [Name]', path: '/components/[name]-playground', type: 'playground', } -
Add Route in
:src/App.tsxconst [Name]PlaygroundContent = lazy(() => import('./components/DemoShowcase/[Name]PlaygroundContent')) <Route path="[name]-playground" element={ <Suspense fallback={<div>Loading...</div>}> <[Name]PlaygroundContent /> </Suspense> } />
Prop Type Mapping Reference
When analyzing TypeScript props, map types to Leva controls:
| TypeScript Type | PropSchema Type | Notes |
|---|---|---|
| | Text input |
| | Slider (add min/max/step) |
| | Checkbox toggle |
| | Dropdown with options array |
| | Extract enum values as options |
| | For simple text children |
| Color strings | | Color picker |
| Skip | Not controllable |
| Complex objects | Skip | Not controllable |
| Skip | Not controllable |
PropSchema Format
import { PropSchema } from '@/components/DemoShowcase/PlaygroundCanvas' const schema: PropSchema = { propName: { type: 'string' | 'number' | 'boolean' | 'select' | 'color', label?: string, // Custom label (defaults to propName) defaultValue?: unknown, // Initial value options?: string[], // For 'select' type min?: number, // For 'number' type max?: number, // For 'number' type step?: number, // For 'number' type } }
Phase 4: Component Updates - Check for Existing Demos
CRITICAL: When updating an existing component or hook, ALWAYS check if demo pages exist:
-
Search for Demo Pages:
- Check
forsrc/components/DemoShowcase/
or[Name]Content.tsx[Name]PlaygroundContent.tsx - Check
forsrc/pages/[Name]Demo.tsx - Check
for entries (includingdemoRegistry.tsx
)type: 'playground'
- Check
-
If Demo Pages Exist:
- Update them to reflect new functionality
- Add examples demonstrating new features
- Update code examples
- Test that demos still work correctly
-
Prompt User:
"I found existing demo pages for this [component/hook]. I'll update them to include the new [feature/changes]."
Demo Content Best Practices
Structure
Organize demo content with clear sections:
<div className="space-y-8"> {/* Example 1: Basic Usage */} <Card className="p-6 space-y-3"> <div className="flex items-center gap-2"> <Badge variant="secondary">Basic</Badge> <span className="text-xs text-zinc-500 dark:text-zinc-400"> Configuration details </span> </div> {/* Demo content */} </Card> {/* More examples... */} {/* Code Example */} <Card className="p-6 space-y-3 bg-zinc-50 dark:bg-zinc-900"> <Badge variant="outline">Usage Example</Badge> <pre className="text-xs text-zinc-700 dark:text-zinc-300 overflow-x-auto"> <code>{`// Code example here`}</code> </pre> </Card> </div>
Example Categories
Include diverse examples:
- Basic - Simple default usage
- Advanced - Complex configurations
- Interactive - User-controlled examples
- Variants - Different visual styles or behaviors
- Edge Cases - Boundary conditions
- Code Examples - Implementation snippets
Styling
- Use Card components for grouping examples
- Add Badge components for labeling examples
- Include configuration details in muted text
- Support dark mode throughout
- Add visual indicators for interactive elements
- Show state changes clearly
Component Showcase Navigation
The navigation is automatically generated from
demoRegistry.tsx:
- Hooks section: Custom React hooks
- Components section: UI components, libraries, demos
Demos are displayed in the order they appear in
DEMO_REGISTRY.
Testing Checklist
After creating or updating component demos:
- Navigate to the demo route
- Verify all examples render correctly
- Test interactive elements (buttons, inputs, controls)
- Check dark mode appearance
- Verify code examples are accurate
- Test on different screen sizes
- Check TypeScript compilation
- Verify navigation active state
Additional Checks for Playgrounds
- Verify Leva props panel appears (top-right corner)
- Test that prop changes update the component in real-time
- Verify navigation collapse toggle works
- Check canvas centering at different sizes
- Test all prop controls (selects, inputs, toggles)
Examples
Example 1: Creating a New Hook with Demo
User: "Create a useDebounce hook" Claude: 1. Asks: "Would you like me to create a demo page for this hook in the component showcase?" 2. User selects: "Yes, create demo page" 3. Creates: - src/hooks/useDebounce.tsx (the hook) - src/components/DemoShowcase/DebounceContent.tsx (demo) - Updates demoRegistry.tsx - Updates App.tsx with route
Example 2: Updating Existing Component
User: "Add a 'size' prop to the Button component" Claude: 1. Searches for existing demos 2. Finds: N/A (Button is shadcn component, no custom demo) 3. Updates Button usage examples in existing demos if needed
Example 3: Updating Hook with Demo
User: "Add a 'delay' option to useTypewriter" Claude: 1. Updates src/hooks/useTypewriter.tsx 2. Searches and finds: src/components/DemoShowcase/TypewriterContent.tsx 3. Announces: "I found the existing TypewriterContent demo. I'll add an example showing the new delay option." 4. Adds new Card with delay example 5. Updates code example to include delay option
Example 4: Creating a Component Playground
User: "Create a playground for the Badge component" Claude: 1. Asks: "Would you like me to create a demo page for this component?" 2. User selects: "Yes, playground" 3. Claude reads src/components/ui/badge.tsx 4. Analyzes BadgeProps interface and presents: "I found these props: **Controllable:** - variant: 'default' | 'secondary' | 'destructive' | 'outline' - children: ReactNode (as string) **Not controllable:** - className: styling (skip) Which props would you like to expose?" 5. User selects: "variant and children" 6. Creates: - src/components/DemoShowcase/BadgePlaygroundContent.tsx - Updates demoRegistry.tsx with type: 'playground' - Updates App.tsx with route
File Locations Reference
- Component showcase layout:
src/pages/ComponentShowcase.tsx - Demo registry:
src/components/DemoShowcase/demoRegistry.tsx - Navigation:
src/components/DemoShowcase/DemoNavigation.tsx - Demo content:
src/components/DemoShowcase/[Name]Content.tsx - Playground content:
src/components/DemoShowcase/[Name]PlaygroundContent.tsx - Playground canvas:
src/components/DemoShowcase/PlaygroundCanvas.tsx - Standalone demos:
src/pages/[Name]Demo.tsx - Routes:
src/App.tsx
Key Principles
- Always ask - Don't assume whether demos are wanted
- Always search - Check for existing demos before updating
- Keep demos updated - When components change, demos should reflect it
- Provide variety - Show multiple use cases, not just basic usage
- Make it interactive - Let users experiment with controls
- Include code - Show implementation examples
- Support dark mode - Test in both themes
- Organize clearly - Use consistent structure across demos