Help us improve
Share bugs, ideas, or general feedback.
From storybook-assistant
Scaffold a new component with story, tests, and optional visual mockup following SOTA patterns
npx claudepluginhub flight505/storybook-assistantHow this command is triggered — by the user, by Claude, or both
Slash command
/storybook-assistant:create-componentThe summary Claude sees in its command listing — used to decide when to auto-load this command
# Create Component Command When the user invokes `/create-component`, guide them through creating a new component with all necessary files: component implementation, Storybook story, tests, and optional visual mockup. ## Workflow Overview This command provides an interactive workflow for scaffolding production-ready components: 1. **Detect Framework**: Auto-detect project framework (React, Vue, Svelte) 2. **Gather Requirements**: Use AskUserQuestion to collect component details 3. **Generate Component**: Create component file with TypeScript/proper types 4. **Generate Story**: Create st...
/create-componentGuides UI component creation: detects framework/styling, asks for name/purpose/complexity/props/state specs, generates code with best practices.
/componentGenerates production-ready React UI components like buttons, cards, modals, forms with design system styles, accessibility, variants. Optional style like Material Design.
/component-generatorGenerates React components from natural language descriptions with TypeScript types, styling (CSS modules/Tailwind), and tests (RTL/Jest/Vitest). Supports --style, --test, --output flags.
/svelte-componentCreates new Svelte components with best practices, proper structure, optional TypeScript support, tests, Storybook stories, and usage docs.
/ux-componentGenerates a single production-grade UI component (button, modal, navbar, etc.) from a user spec, with full interaction states, accessibility, and brand alignment. Triggers on phrases like 'create a [component]'.
/component-scaffoldScaffolds production-ready React or React Native components with TypeScript, tests, styles, accessibility features, and documentation from provided spec.
Share bugs, ideas, or general feedback.
When the user invokes /create-component, guide them through creating a new component with all necessary files: component implementation, Storybook story, tests, and optional visual mockup.
This command provides an interactive workflow for scaffolding production-ready components:
Run framework detection to understand the project setup:
bash ${CLAUDE_PLUGIN_ROOT}/scripts/detect-framework.sh
This provides:
Use AskUserQuestion with serial questions to gather component requirements:
Round 1: Component Category
AskUserQuestion({
questions: [
{
question: "What category of component are you creating?",
header: "Category",
multiSelect: false,
options: [
{
label: "Form Control",
description: "Interactive elements like buttons, inputs, checkboxes"
},
{
label: "Layout",
description: "Containers, cards, grids, modals for structuring content"
},
{
label: "Data Display",
description: "Tables, lists, data grids for showing information"
},
{
label: "Navigation",
description: "Menus, tabs, breadcrumbs for site navigation"
}
]
}
]
})
Round 2: Specific Component Type (Conditional)
After receiving the category answer, ask for specific type. The pattern is:
Pattern Example (Form Control):
AskUserQuestion({
questions: [
// Question 1: Component type (category-specific)
{
question: "Which form control component?",
header: "Type",
multiSelect: false,
options: [
{
label: "Button",
description: "Action button with variants (primary, secondary, etc.)"
},
{
label: "Input",
description: "Text input field with validation and states"
},
{
label: "Checkbox",
description: "Toggle control for boolean options"
},
{
label: "Select",
description: "Dropdown menu for selecting from options"
}
]
},
// Question 2: Component name (same for all categories)
{
question: "What should the component be named? (Use PascalCase)",
header: "Name",
multiSelect: false,
options: [
{
label: "MyButton",
description: "Example name - you can type your own via 'Other'"
},
{
label: "UserCard",
description: "Example name - you can type your own via 'Other'"
}
]
},
// Question 3: Testing level (same for all categories)
{
question: "What level of testing should I include?",
header: "Test Level",
multiSelect: false,
options: [
{
label: "Full Testing",
description: "Recommended: Component + Story + Interaction tests + A11y tests"
},
{
label: "Standard Testing",
description: "Component + Story + Interaction tests"
},
{
label: "Basic",
description: "Component + Story only"
},
{
label: "Minimal",
description: "Component only (no story or tests)"
}
]
},
// Question 4: Visual mockup (same for all categories)
{
question: "Should I generate a visual mockup for design reference?",
header: "Mockup",
multiSelect: false,
options: [
{
label: "Yes",
description: "Recommended: Creates AI mockup (requires OPENROUTER_API_KEY)"
},
{
label: "No",
description: "Generate component files only"
}
]
}
]
})
Other Category Options (Question 1 varies by category):
// Layout category options:
{
question: "Which layout component?",
header: "Type",
options: [
{ label: "Card", description: "Content container with optional header and footer" },
{ label: "Modal", description: "Overlay dialog with backdrop and focus management" },
{ label: "Container", description: "Layout wrapper with max-width and padding" },
{ label: "Grid", description: "Responsive grid system for complex layouts" }
]
}
// Data Display category options:
{
question: "Which data display component?",
header: "Type",
options: [
{ label: "Table", description: "Data table with sorting, filtering, pagination" },
{ label: "List", description: "Vertical list with optional icons and actions" },
{ label: "DataGrid", description: "Advanced table with inline editing and grouping" },
{ label: "Chart", description: "Data visualization component (requires chart library)" }
]
}
// Navigation category options:
{
question: "Which navigation component?",
header: "Type",
options: [
{ label: "Menu", description: "Dropdown or sidebar menu with nested items" },
{ label: "Tabs", description: "Horizontal or vertical tab navigation" },
{ label: "Breadcrumb", description: "Page location breadcrumb trail" },
{ label: "Navbar", description: "Top navigation bar with logo and links" }
]
}
Note: Questions 2-4 (Name, Testing, Mockup) are identical across all categories. Only Question 1 (component type) varies based on the category selected in Round 1.
After receiving answers from both rounds, process and prepare for generation:
import json
import os
# Extract answers from Round 1 (Category)
component_category = answers_round1['What category of component are you creating?']
# Extract answers from Round 2 (Type and preferences)
# Question text varies by category, use the actual question text as key
component_type = answers_round2['Which form control component?'] # Or 'Which layout component?', etc.
component_name_raw = answers_round2['What should the component be named? (Use PascalCase)']
testing_level_raw = answers_round2['What level of testing should I include?']
generate_mockup_raw = answers_round2['Should I generate a visual mockup for design reference?']
# Clean component name (from "Other" text input)
component_name = component_name_raw.strip()
# Validate component name (PascalCase)
if not component_name[0].isupper():
component_name = component_name[0].upper() + component_name[1:]
# Map testing level
testing_level_map = {
"Full Testing": "full",
"Standard Testing": "standard",
"Basic": "basic",
"Minimal": "minimal"
}
testing_level = testing_level_map.get(testing_level_raw, "full")
# Determine if mockup should be generated
generate_mockup = "Yes" in generate_mockup_raw and os.getenv('OPENROUTER_API_KEY')
# Get component template based on type
component_template = get_component_template(component_type, framework)
Invoke the component scaffold script:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/component-scaffold/scripts/create_component.py \
--name "${COMPONENT_NAME}" \
--type "${COMPONENT_TYPE}" \
--framework "${FRAMEWORK}" \
--typescript \
--output "${COMPONENT_DIR}/${COMPONENT_NAME}.tsx"
This creates the component file with:
Use the existing story generation system:
python3 ${CLAUDE_PLUGIN_ROOT}/skills/story-generation/scripts/generate_story.py \
"${COMPONENT_DIR}/${COMPONENT_NAME}.tsx" \
--level "${TESTING_LEVEL}" \
--output "${COMPONENT_DIR}/${COMPONENT_NAME}.stories.tsx"
If user requested mockup and OPENROUTER_API_KEY is available:
# Build context-aware prompt based on component type and project
mockup_prompt = f"""
Modern {component_type} component for {framework} application.
Component name: {component_name}
Style: Clean, professional, follows design system best practices
Include: {get_type_specific_elements(component_type)}
Color scheme: Modern, accessible (WCAG AA compliant)
Layout: Responsive, mobile-friendly
"""
# Generate mockup
python3 ${CLAUDE_PLUGIN_ROOT}/skills/visual-design/scripts/generate_mockup.py \
"${mockup_prompt}" \
--model "google/gemini-3.0-pro-image" \
--output "${COMPONENT_DIR}/mockups/${COMPONENT_NAME}.png"
Show the user what was created:
═══════════════════════════════════════════════
Component Created: ${COMPONENT_NAME}
═══════════════════════════════════════════════
Type: ${COMPONENT_TYPE}
Framework: ${FRAMEWORK}
Files Created:
✓ ${COMPONENT_DIR}/${COMPONENT_NAME}.tsx
✓ ${COMPONENT_DIR}/${COMPONENT_NAME}.stories.tsx
${MOCKUP_CREATED ? `✓ ${COMPONENT_DIR}/mockups/${COMPONENT_NAME}.png` : ''}
Component Features:
✓ TypeScript interfaces with proper types
✓ Accessibility attributes (ARIA labels, roles)
✓ ${PROPS_COUNT} props with sensible defaults
✓ JSDoc documentation
${TESTING_LEVEL === 'full' ? '✓ Interaction tests with play functions' : ''}
${TESTING_LEVEL === 'full' ? '✓ Accessibility tests with axe-core' : ''}
Next Steps:
1. Review component: ${COMPONENT_DIR}/${COMPONENT_NAME}.tsx
2. Customize props and styling as needed
3. Run Storybook: npm run storybook
4. View your component in the browser
${TESTING_LEVEL !== 'minimal' ? '5. Run tests: npm run test-storybook' : ''}
Features:
Props Generated:
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
size?: 'small' | 'medium' | 'large';
disabled?: boolean;
loading?: boolean;
icon?: React.ReactNode;
iconPosition?: 'left' | 'right';
onClick?: () => void;
children: React.ReactNode;
}
Features:
Props Generated:
interface InputProps {
label: string;
type?: 'text' | 'email' | 'password' | 'number';
placeholder?: string;
value?: string;
error?: string;
helperText?: string;
required?: boolean;
disabled?: boolean;
onChange?: (value: string) => void;
}
Features:
Props Generated:
interface CardProps {
variant?: 'elevated' | 'outlined' | 'flat';
image?: string;
imageAlt?: string;
header?: React.ReactNode;
footer?: React.ReactNode;
onClick?: () => void;
children: React.ReactNode;
}
Features:
Props Generated:
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title?: string;
size?: 'small' | 'medium' | 'large' | 'fullscreen';
closeOnBackdropClick?: boolean;
closeOnEsc?: boolean;
children: React.ReactNode;
}
Features:
Props Generated:
interface TableColumn<T> {
key: keyof T;
header: string;
sortable?: boolean;
render?: (value: T[keyof T], row: T) => React.ReactNode;
}
interface TableProps<T> {
data: T[];
columns: TableColumn<T>[];
sortable?: boolean;
selectable?: boolean;
pagination?: boolean;
pageSize?: number;
loading?: boolean;
emptyMessage?: string;
onRowClick?: (row: T) => void;
}
For "Custom" type, ask follow-up questions:
AskUserQuestion({
questions: [
{
question: "What props does your component need? (comma-separated, e.g., 'title, description, onClick')",
header: "Component Props",
multiSelect: false,
options: [
{
label: "Enter prop names",
description: "List props separated by commas"
}
]
},
{
question: "Should this component accept children?",
header: "Children Support",
multiSelect: false,
options: [
{
label: "Yes - Component wraps content",
description: "Add children prop (React.ReactNode)"
},
{
label: "No - Self-contained component",
description: "No children prop"
}
]
}
]
})
import React from 'react';
import './{{COMPONENT_NAME}}.css';
export interface {{COMPONENT_NAME}}Props {
{{PROPS}}
}
/**
* {{COMPONENT_DESCRIPTION}}
*/
export function {{COMPONENT_NAME}}({
{{PROP_DESTRUCTURING}}
}: {{COMPONENT_NAME}}Props) {
{{COMPONENT_LOGIC}}
return (
<div className="{{COMPONENT_CLASS}}" {{ATTRIBUTES}}>
{{COMPONENT_CONTENT}}
</div>
);
}
{{COMPONENT_NAME}}.displayName = '{{COMPONENT_NAME}}';
<script setup lang="ts">
interface {{COMPONENT_NAME}}Props {
{{PROPS}}
}
const props = defineProps<{{COMPONENT_NAME}}Props>();
{{COMPONENT_LOGIC}}
</script>
<template>
<div class="{{COMPONENT_CLASS}}" {{ATTRIBUTES}}>
{{COMPONENT_CONTENT}}
</div>
</template>
<style scoped>
.{{COMPONENT_CLASS}} {
{{BASE_STYLES}}
}
</style>
<script lang="ts">
export let {{PROPS}};
{{COMPONENT_LOGIC}}
</script>
<div class="{{COMPONENT_CLASS}}" {{ATTRIBUTES}}>
{{COMPONENT_CONTENT}}
</div>
<style>
.{{COMPONENT_CLASS}} {
{{BASE_STYLES}}
}
</style>
The script provides sensible defaults based on component type:
| Type | Default Props | Variants | Features |
|---|---|---|---|
| Button | variant, size, disabled, loading, onClick, children | 4 variants, 3 sizes | Icon support, loading state |
| Input | label, type, value, error, onChange | 4 types | Validation, helper text |
| Card | variant, image, header, footer, children | 3 variants | Clickable, image support |
| Modal | isOpen, onClose, title, size, children | 4 sizes | Focus trap, ESC/backdrop close |
| Table | data, columns, sortable, pagination | - | Sorting, selection, pagination |
| Form | onSubmit, loading, error | - | Validation, error handling |
| Navigation | items, activeItem, onChange | - | Routing support |
| Layout | children, spacing, direction | - | Flex/Grid layout |
Component Already Exists:
⚠ Component already exists: src/components/Button.tsx
Options:
1. Choose a different name
2. Overwrite existing (use --force flag)
3. Cancel operation
Invalid Component Name:
✗ Invalid component name: "my-button"
Component names must:
• Start with uppercase letter (PascalCase)
• Contain only letters and numbers
• Not contain spaces or special characters
Examples: MyButton, UserCard, DataTable
Framework Detection Failed:
✗ Could not detect project framework
Please specify framework manually:
/create-component --framework react
/create-component --framework vue
/create-component --framework svelte
No Component Directory:
⚠ Could not find component directory
Suggested directories:
• src/components
• src/lib/components
• components
Create directory? (y/n)
# Custom props
/create-component --name MyButton --type button --props "label:string,onClick:function,disabled:boolean"
# Specify output directory
/create-component --name UserCard --type card --output src/features/user/components
# Generate component with custom variants
/create-component --name StatusBadge --type custom --variants "success,warning,error,info"
If project uses Tauri, automatically include IPC mocking in stories:
// Auto-generated in story file
export const WithTauriAPI: Story = {
args: { /* ... */ },
decorators: [
(Story) => {
if (typeof window !== 'undefined') {
window.__TAURI__ = {
invoke: async (cmd) => ({ success: true }),
};
}
return <Story />;
},
],
};
If project uses Electron, include IPC mocking:
// Auto-generated in story file
export const WithElectronAPI: Story = {
args: { /* ... */ },
decorators: [
(Story) => {
if (typeof window !== 'undefined') {
window.api = {
// Mock electron API
};
}
return <Story />;
},
],
};