Build production-grade, accessible, and tested component libraries with Storybook, Chromatic, and design tokens
Build production-ready React component libraries using Storybook for documentation and Chromatic for visual testing. Use this when creating reusable, accessible components with design tokens and automated publishing workflows.
/plugin marketplace add pluginagentmarketplace/custom-plugin-react/plugin install react-developer-roadmap@pluginagentmarketplace-reactThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/config.yamlreferences/GUIDE.mdscripts/helper.pyLearn to build reusable, accessible, and well-documented component libraries for React applications using modern design patterns and tools.
// Good: Flexible API
<Card>
<Card.Header>
<Card.Title>Title</Card.Title>
</Card.Header>
<Card.Body>Content</Card.Body>
<Card.Footer>
<Button>Action</Button>
</Card.Footer>
</Card>
// Bad: Rigid API
<Card title="Title" content="Content" action="Action" />
function Button({ children, onClick, disabled, ...props }) {
return (
<button
type="button"
onClick={onClick}
disabled={disabled}
aria-disabled={disabled}
{...props}
>
{children}
</button>
);
}
const Button = forwardRef(({
children,
variant = 'primary',
size = 'md',
disabled = false,
loading = false,
leftIcon,
rightIcon,
...props
}, ref) => {
return (
<button
ref={ref}
className={`btn btn-${variant} btn-${size}`}
disabled={disabled || loading}
aria-busy={loading}
{...props}
>
{leftIcon && <span className="btn-icon-left">{leftIcon}</span>}
{loading ? <Spinner size="sm" /> : children}
{rightIcon && <span className="btn-icon-right">{rightIcon}</span>}
</button>
);
});
Button.displayName = 'Button';
const Input = forwardRef(({
label,
error,
helper,
required,
...props
}, ref) => {
const id = useId();
return (
<div className="input-wrapper">
{label && (
<label htmlFor={id}>
{label}
{required && <span aria-label="required">*</span>}
</label>
)}
<input
ref={ref}
id={id}
aria-invalid={!!error}
aria-describedby={error ? `${id}-error` : helper ? `${id}-helper` : undefined}
{...props}
/>
{helper && <span id={`${id}-helper`} className="input-helper">{helper}</span>}
{error && <span id={`${id}-error`} className="input-error" role="alert">{error}</span>}
</div>
);
});
function Modal({ isOpen, onClose, title, children }) {
const modalRef = useRef(null);
useEffect(() => {
if (isOpen) {
const previousActiveElement = document.activeElement;
modalRef.current?.focus();
return () => {
previousActiveElement?.focus();
};
}
}, [isOpen]);
useOnClickOutside(modalRef, onClose);
if (!isOpen) return null;
return createPortal(
<div className="modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<div ref={modalRef} className="modal" tabIndex={-1}>
<div className="modal-header">
<h2 id="modal-title">{title}</h2>
<button onClick={onClose} aria-label="Close modal">×</button>
</div>
<div className="modal-body">{children}</div>
</div>
</div>,
document.body
);
}
function Dropdown({ trigger, children }) {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
useOnClickOutside(dropdownRef, () => setIsOpen(false));
return (
<div ref={dropdownRef} className="dropdown">
<div onClick={() => setIsOpen(!isOpen)} role="button" aria-expanded={isOpen}>
{trigger}
</div>
{isOpen && (
<div className="dropdown-menu" role="menu">
{children}
</div>
)}
</div>
);
}
function DropdownItem({ onClick, children }) {
return (
<div className="dropdown-item" role="menuitem" onClick={onClick} tabIndex={0}>
{children}
</div>
);
}
Dropdown.Item = DropdownItem;
const TabsContext = createContext();
function Tabs({ children, defaultTab }) {
const [activeTab, setActiveTab] = useState(defaultTab);
return (
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
);
}
function TabList({ children }) {
return <div className="tab-list" role="tablist">{children}</div>;
}
function Tab({ id, children }) {
const { activeTab, setActiveTab } = useContext(TabsContext);
return (
<button
role="tab"
aria-selected={activeTab === id}
onClick={() => setActiveTab(id)}
className={activeTab === id ? 'active' : ''}
>
{children}
</button>
);
}
function TabPanels({ children }) {
return <div className="tab-panels">{children}</div>;
}
function TabPanel({ id, children }) {
const { activeTab } = useContext(TabsContext);
if (activeTab !== id) return null;
return <div role="tabpanel">{children}</div>;
}
Tabs.List = TabList;
Tabs.Tab = Tab;
Tabs.Panels = TabPanels;
Tabs.Panel = TabPanel;
npx storybook@latest init
// Button.stories.jsx
import { Button } from './Button';
export default {
title: 'Components/Button',
component: Button,
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'danger']
},
size: {
control: 'select',
options: ['sm', 'md', 'lg']
}
}
};
export const Primary = {
args: {
variant: 'primary',
children: 'Button'
}
};
export const WithIcons = {
args: {
leftIcon: <Icon name="star" />,
children: 'Button'
}
};
export const Loading = {
args: {
loading: true,
children: 'Loading...'
}
};
// Button.tsx
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ children, variant = 'primary', size = 'md', ...props }, ref) => {
return (
<button ref={ref} className={`btn btn-${variant} btn-${size}`} {...props}>
{children}
</button>
);
}
);
{
"name": "@yourname/component-library",
"version": "1.0.0",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Difficulty: Intermediate to Advanced Estimated Time: 3-4 weeks Prerequisites: React Fundamentals, Component Architecture
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.