Skills · Design & UI

Web Component Design

Unverified30/40

Master React, Vue, and Svelte component patterns including CSS-in-JS, composition strategies, and reusable component architecture. Use when building UI component libraries, designing component APIs, or implementing frontend design systems.

Originally by wshobson · MIT

Claude CodePartialHas SKILL.md but declares no allowed-tools — Claude Code will ask for permission each time
CursorPartialPlain prose you can paste in — but no Cursor rules file
CodexPartialPlain prose you can paste in — but no AGENTS.md
Gemini CLIPartialPlain prose you can paste in
CopilotPartialPlain prose you can paste in — but no Copilot instructions file
npx agentalley add web-component-design

This command does not work yet — the CLI is still being built. Until then, use Raw in the reader below to take the file.

Who is stuck, and on what

Master React, Vue, and Svelte component patterns including CSS-in-JS, composition strategies, and reusable component architecture. Use when building UI component libraries, designing component APIs, or implementing frontend design systems.

The whole source

No sign-in, no blur, nothing truncated
web-component-design/SKILL.md272 lines7.3 KBRawView on GitHub
Frontmatter — 2 properties
nameweb-component-design
descriptionMaster React, Vue, and Svelte component patterns including CSS-in-JS, composition strategies, and reusable component architecture. Use when building UI component libraries, designing component APIs, or implementing frontend design systems.
1---
2name: web-component-design
3description: Master React, Vue, and Svelte component patterns including CSS-in-JS, composition strategies, and reusable component architecture. Use when building UI component libraries, designing component APIs, or implementing frontend design systems.
4---A5No allowed-tools declared — no way to tell what this skill may touch
5 
6# Web Component Design
7 
8Build reusable, maintainable UI components using modern frameworks with clean composition patterns and styling approaches.
9 
10## When to Use This Skill
11 
12- Designing reusable component libraries or design systems
13- Implementing complex component composition patterns
14- Choosing and applying CSS-in-JS solutions
15- Building accessible, responsive UI components
16- Creating consistent component APIs across a codebase
17- Refactoring legacy components into modern patterns
18- Implementing compound components or render props
19 
20## Core Concepts
21 
22### 1. Component Composition Patterns
23 
24**Compound Components**: Related components that work together
25 
26```tsx
27// Usage
28<Select value={value} onChange={setValue}>
29 <Select.Trigger>Choose option</Select.Trigger>
30 <Select.Options>
31 <Select.Option value="a">Option A</Select.Option>
32 <Select.Option value="b">Option B</Select.Option>
33 </Select.Options>
34</Select>
35```
36 
37**Render Props**: Delegate rendering to parent
38 
39```tsx
40<DataFetcher url="/api/users">
41 {({ data, loading, error }) =>
42 loading ? <Spinner /> : <UserList users={data} />
43 }
44</DataFetcher>
45```
46 
47**Slots (Vue/Svelte)**: Named content injection points
48 
49```vue
50<template>
51 <Card>
52 <template #header>Title</template>
53 <template #content>Body text</template>
54 <template #footer><Button>Action</Button></template>
55 </Card>
56</template>
57```
58 
59### 2. CSS-in-JS Approaches
60 
61| Solution | Approach | Best For |
62| --------------------- | ---------------------- | --------------------------------- |
63| **Tailwind CSS** | Utility classes | Rapid prototyping, design systems |
64| **CSS Modules** | Scoped CSS files | Existing CSS, gradual adoption |
65| **styled-components** | Template literals | React, dynamic styling |
66| **Emotion** | Object/template styles | Flexible, SSR-friendly |
67| **Vanilla Extract** | Zero-runtime | Performance-critical apps |
68 
69### 3. Component API Design
70 
71```tsx
72interface ButtonProps {
73 variant?: "primary" | "secondary" | "ghost";
74 size?: "sm" | "md" | "lg";
75 isLoading?: boolean;
76 isDisabled?: boolean;
77 leftIcon?: React.ReactNode;
78 rightIcon?: React.ReactNode;
79 children: React.ReactNode;
80 onClick?: () => void;
81}
82```
83 
84**Principles**:
85 
86- Use semantic prop names (`isLoading` vs `loading`)
87- Provide sensible defaults
88- Support composition via `children`
89- Allow style overrides via `className` or `style`
90 
91## Quick Start: React Component with Tailwind
92 
93```tsx
94import { forwardRef, type ComponentPropsWithoutRef } from "react";
95import { cva, type VariantProps } from "class-variance-authority";
96import { cn } from "@/lib/utils";
97 
98const buttonVariants = cva(
99 "inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50",
100 {
101 variants: {
102 variant: {
103 primary: "bg-blue-600 text-white hover:bg-blue-700",
104 secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200",
105 ghost: "hover:bg-gray-100 hover:text-gray-900",
106 },
107 size: {
108 sm: "h-8 px-3 text-sm",
109 md: "h-10 px-4 text-sm",
110 lg: "h-12 px-6 text-base",
111 },
112 },
113 defaultVariants: {
114 variant: "primary",
115 size: "md",
116 },
117 },
118);
119 
120interface ButtonProps
121 extends
122 ComponentPropsWithoutRef<"button">,
123 VariantProps<typeof buttonVariants> {
124 isLoading?: boolean;
125}
126 
127export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
128 ({ className, variant, size, isLoading, children, ...props }, ref) => (
129 <button
130 ref={ref}
131 className={cn(buttonVariants({ variant, size }), className)}
132 disabled={isLoading || props.disabled}
133 {...props}
134 >
135 {isLoading && <Spinner className="mr-2 h-4 w-4" />}
136 {children}
137 </button>
138 ),
139);
140Button.displayName = "Button";
141```
142 
143## Framework Patterns
144 
145### React: Compound Components
146 
147```tsx
148import { createContext, useContext, useState, type ReactNode } from "react";
149 
150interface AccordionContextValue {
151 openItems: Set<string>;
152 toggle: (id: string) => void;
153}
154 
155const AccordionContext = createContext<AccordionContextValue | null>(null);
156 
157function useAccordion() {
158 const context = useContext(AccordionContext);
159 if (!context) throw new Error("Must be used within Accordion");
160 return context;
161}
162 
163export function Accordion({ children }: { children: ReactNode }) {
164 const [openItems, setOpenItems] = useState<Set<string>>(new Set());
165 
166 const toggle = (id: string) => {
167 setOpenItems((prev) => {
168 const next = new Set(prev);
169 next.has(id) ? next.delete(id) : next.add(id);
170 return next;
171 });
172 };
173 
174 return (
175 <AccordionContext.Provider value={{ openItems, toggle }}>
176 <div className="divide-y">{children}</div>
177 </AccordionContext.Provider>
178 );
179}
180 
181Accordion.Item = function AccordionItem({
182 id,
183 title,
184 children,
185}: {
186 id: string;
187 title: string;
188 children: ReactNode;
189}) {
190 const { openItems, toggle } = useAccordion();
191 const isOpen = openItems.has(id);
192 
193 return (
194 <div>
195 <button onClick={() => toggle(id)} className="w-full text-left py-3">
196 {title}
197 </button>
198 {isOpen && <div className="pb-3">{children}</div>}
199 </div>
200 );
201};
202```
203 
204### Vue 3: Composables
205 
206```vue
207<script setup lang="ts">
208import { ref, computed, provide, inject, type InjectionKey } from "vue";
209 
210interface TabsContext {
211 activeTab: Ref<string>;
212 setActive: (id: string) => void;
213}
214 
215const TabsKey: InjectionKey<TabsContext> = Symbol("tabs");
216 
217// Parent component
218const activeTab = ref("tab-1");
219provide(TabsKey, {
220 activeTab,
221 setActive: (id: string) => {
222 activeTab.value = id;
223 },
224});
225 
226// Child component usage
227const tabs = inject(TabsKey);
228const isActive = computed(() => tabs?.activeTab.value === props.id);
229</script>
230```
231 
232### Svelte 5: Runes
233 
234```svelte
235<script lang="ts">
236 interface Props {
237 variant?: 'primary' | 'secondary';
238 size?: 'sm' | 'md' | 'lg';
239 onclick?: () => void;
240 children: import('svelte').Snippet;
241 }
242 
243 let { variant = 'primary', size = 'md', onclick, children }: Props = $props();
244 
245 const classes = $derived(
246 `btn btn-${variant} btn-${size}`
247 );
248</script>
249 
250<button class={classes} {onclick}>
251 {@render children()}
252</button>
253```
254 
255## Best Practices
256 
2571. **Single Responsibility**: Each component does one thing well
2582. **Prop Drilling Prevention**: Use context for deeply nested data
2593. **Accessible by Default**: Include ARIA attributes, keyboard support
2604. **Controlled vs Uncontrolled**: Support both patterns when appropriate
2615. **Forward Refs**: Allow parent access to DOM nodes
2626. **Memoization**: Use `React.memo`, `useMemo` for expensive renders
2637. **Error Boundaries**: Wrap components that may fail
264 
265## Common Issues
266 
267- **Prop Explosion**: Too many props - consider composition instead
268- **Style Conflicts**: Use scoped styles or CSS Modules
269- **Re-render Cascades**: Profile with React DevTools, memo appropriately
270- **Accessibility Gaps**: Test with screen readers and keyboard navigation
271- **Bundle Size**: Tree-shake unused component variants
272 

Reviews

Installed this one?Write the first review and take the Trailblazer badge.

Reviews only open after a real install, so this is empty — and we leave it empty rather than invent one.

Alternatives

Also in Design & UI