Claude-skill-registry component-composition
Component composition patterns with nesting, slots, compound components, and render props. Use when creating reusable components, component APIs, or complex component hierarchies.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
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-composition" ~/.claude/skills/majiayu000-claude-skill-registry-component-composition && rm -rf "$T"
manifest:
skills/data/component-composition/SKILL.mdsource content
Component Composition
Advanced composition patterns for scalable components.
Agent Workflow (MANDATORY)
Before implementation:
- fuse-ai-pilot:explore-codebase - Check existing composition patterns
- fuse-ai-pilot:research-expert - React 19 composition patterns
After: Run fuse-ai-pilot:sniper for validation.
Pattern Overview
| Pattern | Use Case | Complexity |
|---|---|---|
| Children | Simple containers | Low |
| Slots | Named regions | Medium |
| Compound | Related sub-components | Medium |
| Render Props | Custom rendering | High |
| Context | Shared state | High |
1. Children Pattern (Basic)
function Card({ children, className }: { children: React.ReactNode }) { return ( <div className={cn("bg-surface rounded-2xl p-6", className)}> {children} </div> ); } // Usage <Card> <h2>Title</h2> <p>Content</p> </Card>
2. Slots Pattern
interface CardProps { header?: React.ReactNode; footer?: React.ReactNode; children: React.ReactNode; } function Card({ header, footer, children }: CardProps) { return ( <div className="bg-surface rounded-2xl overflow-hidden"> {header && ( <div className="px-6 py-4 border-b border-border"> {header} </div> )} <div className="p-6">{children}</div> {footer && ( <div className="px-6 py-4 border-t border-border bg-muted/50"> {footer} </div> )} </div> ); } // Usage <Card header={<h2>Settings</h2>} footer={<Button>Save</Button>} > <p>Card content here</p> </Card>
3. Compound Components
const CardContext = createContext<{ variant: string }>({ variant: "default" }); function Card({ children, variant = "default" }) { return ( <CardContext.Provider value={{ variant }}> <div className="bg-surface rounded-2xl">{children}</div> </CardContext.Provider> ); } Card.Header = function CardHeader({ children }) { return <div className="px-6 py-4 border-b">{children}</div>; }; Card.Body = function CardBody({ children }) { return <div className="p-6">{children}</div>; }; Card.Footer = function CardFooter({ children }) { const { variant } = useContext(CardContext); return ( <div className={cn("px-6 py-4", variant === "glass" && "bg-white/5")}> {children} </div> ); }; // Usage <Card variant="glass"> <Card.Header> <h2>Title</h2> </Card.Header> <Card.Body> <p>Content</p> </Card.Body> <Card.Footer> <Button>Action</Button> </Card.Footer> </Card>
4. Render Props
interface ListProps<T> { items: T[]; renderItem: (item: T, index: number) => React.ReactNode; renderEmpty?: () => React.ReactNode; } function List<T>({ items, renderItem, renderEmpty }: ListProps<T>) { if (items.length === 0) { return renderEmpty?.() ?? <p>No items</p>; } return ( <ul className="space-y-2"> {items.map((item, i) => ( <li key={i}>{renderItem(item, i)}</li> ))} </ul> ); } // Usage <List items={users} renderItem={(user) => <UserCard user={user} />} renderEmpty={() => <EmptyState message="No users found" />} />
5. As Prop (Polymorphic)
type ButtonProps<T extends React.ElementType> = { as?: T; children: React.ReactNode; } & React.ComponentPropsWithoutRef<T>; function Button<T extends React.ElementType = "button">({ as, children, ...props }: ButtonProps<T>) { const Component = as || "button"; return ( <Component className="px-4 py-2 bg-primary text-primary-foreground rounded-lg" {...props} > {children} </Component> ); } // Usage <Button>Click me</Button> <Button as="a" href="/link">Link button</Button> <Button as={Link} to="/route">Router link</Button>
6. Forwarded Refs
const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => { return ( <input ref={ref} className="w-full px-4 py-2 rounded-lg border" {...props} /> ); }); Input.displayName = "Input"; // Usage with ref const inputRef = useRef<HTMLInputElement>(null); <Input ref={inputRef} />
Composition Guidelines
| DO | DON'T |
|---|---|
| Use children for simple nesting | Over-engineer simple components |
| Use slots for named regions | Use too many slots (max 3-4) |
| Use compound for related parts | Create deep nesting (max 2 levels) |
| Forward refs for form elements | Forget displayName |
Validation
[ ] Appropriate pattern for complexity [ ] TypeScript props properly typed [ ] displayName set on forwardRef [ ] Context used sparingly [ ] Max 2-3 composition levels [ ] Documented API in JSDoc
References
- Component patterns../../references/design-patterns.md
- Production examples../../references/component-examples.md