Back to UI/UX Design

web-component-design

web componentsUI developmentReactVueSveltedesign systemsCSS-in-JScomponent architecture
36.8k📄 MIT🕒 2026-06-16Source ↗

Install this skill

npx skills add wshobson/agents

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Web component design focuses on building modular UI units that prioritize extensibility and consistent state management. Instead of building monolithic pages, this skill emphasizes crafting standalone building blocks—such as compound components, controlled inputs, and slot-based wrappers—that allow developers to assemble interfaces declaratively. By applying structural patterns like render props or context-based item discovery, you separate the underlying logic from the visual presentation. This systematic approach reduces technical debt in large repositories by ensuring prop interfaces remain predictable and style encapsulation remains strict. Whether defining design tokens for a global system or creating highly flexible data-fetching wrappers, this skill ensures that individual interface parts remain decoupled from the host application, allowing them to scale across multiple projects or complex internal dashboards without creating tight coupling or repetitive code paths.

When to Use This Skill

  • Developing internal design systems or shared component libraries
  • Refactoring bloated legacy class components into modular functions
  • Building flexible navigation or accordion systems with sub-components
  • Creating UI parts that handle complex data orchestration internally

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • Refactor this list into a compound component pattern
  • Create a reusable button variant using class-variance-authority
  • Design a controlled input wrapper for our form library
  • Suggest an API interface for a complex card component
  • Convert this logic into a render prop pattern

Pro Tips

  • 💡Always prioritize accessibility from the outset; well-designed components are inherently inclusive and usable for everyone.
  • 💡When designing component APIs, aim for simplicity and predictability, mirroring native HTML elements or established patterns where appropriate for ease of use.
  • 💡Embrace tools like Storybook for isolated development, visual testing, and comprehensive documentation of your components, ensuring consistency and accelerated development.

What this skill does

  • Construction of compound component patterns for shared state
  • Implementation of prop-driven visual variants using utility-first styling
  • Establishment of strict TypeScript interfaces for component APIs
  • Application of render prop patterns to offload display logic
  • Normalization of component behavior through consistent prop naming

When not to use it

  • Simple prototypes where static HTML and minimal CSS suffice
  • Single-use UI blocks that do not require state or lifecycle logic

Example workflow

  1. Define the component prop interface using TypeScript
  2. Create style variants using a library like CVA or Tailwind
  3. Implement the base component with structural slots or children
  4. Wrap child elements in context if sharing state is required
  5. Add documentation and default exports for the library consumer

Prerequisites

  • Proficiency in TypeScript
  • Basic knowledge of UI component frameworks like React, Vue, or Svelte

Pitfalls & limitations

  • !Over-engineering simple components that do not need context
  • !Creating overly restrictive prop APIs that break under edge cases
  • !Forgetting to forward refs, breaking parent interactions

FAQ

What is the primary benefit of a compound component?
It allows parent and child components to share internal state implicitly, which results in a cleaner, more declarative markup for the end user.
When should I use render props?
Use them when a component needs to delegate its rendering logic to the parent, often to share data fetched by the component itself.
How do I ensure my component styling remains consistent?
Define a set of variants (e.g., primary, secondary) using a tool like CVA and apply them through a standardized tailwind utility chain.

How it compares

Generic prompts often produce unstyled or inconsistent code; this skill provides a structured architecture that enforces type safety, state management, and clear API boundaries.

Source & trust

37k stars📄 MIT🕒 Updated 2026-06-16
📄 Full skill instructions — original source: wshobson/agents
# Web Component Design

Build reusable, maintainable UI components using modern frameworks with clean composition patterns and styling approaches.

## When to Use This Skill

- Designing reusable component libraries or design systems
- Implementing complex component composition patterns
- Choosing and applying CSS-in-JS solutions
- Building accessible, responsive UI components
- Creating consistent component APIs across a codebase
- Refactoring legacy components into modern patterns
- Implementing compound components or render props

## Core Concepts

### 1. Component Composition Patterns

**Compound Components**: Related components that work together

// Usage
<Select value={value} onChange={setValue}>
<Select.Trigger>Choose option</Select.Trigger>
<Select.Options>
<Select.Option value="a">Option A</Select.Option>
<Select.Option value="b">Option B</Select.Option>
</Select.Options>
</Select>


**Render Props**: Delegate rendering to parent

<DataFetcher url="/api/users">
{({ data, loading, error }) =>
loading ? <Spinner /> : <UserList users={data} />
}
</DataFetcher>


**Slots (Vue/Svelte)**: Named content injection points

<template>
<Card>
<template #header>Title</template>
<template #content>Body text</template>
<template #footer><Button>Action</Button></template>
</Card>
</template>


### 2. CSS-in-JS Approaches

| Solution | Approach | Best For |
| --------------------- | ---------------------- | --------------------------------- |
| **Tailwind CSS** | Utility classes | Rapid prototyping, design systems |
| **CSS Modules** | Scoped CSS files | Existing CSS, gradual adoption |
| **styled-components** | Template literals | React, dynamic styling |
| **Emotion** | Object/template styles | Flexible, SSR-friendly |
| **Vanilla Extract** | Zero-runtime | Performance-critical apps |

### 3. Component API Design

interface ButtonProps {
variant?: "primary" | "secondary" | "ghost";
size?: "sm" | "md" | "lg";
isLoading?: boolean;
isDisabled?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
children: React.ReactNode;
onClick?: () => void;
}


**Principles**:

- Use semantic prop names (isLoading vs loading)
- Provide sensible defaults
- Support composition via children
- Allow style overrides via className or style

## Quick Start: React Component with Tailwind

import { forwardRef, type ComponentPropsWithoutRef } from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const buttonVariants = cva(
"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",
{
variants: {
variant: {
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200",
ghost: "hover:bg-gray-100 hover:text-gray-900",
},
size: {
sm: "h-8 px-3 text-sm",
md: "h-10 px-4 text-sm",
lg: "h-12 px-6 text-base",
},
},
defaultVariants: {
variant: "primary",
size: "md",
},
},
);

interface ButtonProps
extends
ComponentPropsWithoutRef<"button">,
VariantProps<typeof buttonVariants> {
isLoading?: boolean;
}

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, isLoading, children, ...props }, ref) => (
<button
ref={ref}
className={cn(buttonVariants({ variant, size }), className)}
disabled={isLoading || props.disabled}
{...props}
>
{isLoading && <Spinner className="mr-2 h-4 w-4" />}
{children}
</button>
),
);
Button.displayName = "Button";


## Framework Patterns

### React: Compound Components

import { createContext, useContext, useState, type ReactNode } from "react";

interface AccordionContextValue {
openItems: Set<string>;
toggle: (id: string) => void;
}

const AccordionContext = createContext<AccordionContextValue | null>(null);

function useAccordion() {
const context = useContext(AccordionContext);
if (!context) throw new Error("Must be used within Accordion");
return context;
}

export function Accordion({ children }: { children: ReactNode }) {
const [openItems, setOpenItems] = useState<Set<string>>(new Set());

const toggle = (id: string) => {
setOpenItems((prev) => {
const next = new Set(prev);
next.has(id) ? next.delete(id) : next.add(id);
return next;
});
};

return (
<AccordionContext.Provider value={{ openItems, toggle }}>
<div className="divide-y">{children}</div>
</AccordionContext.Provider>
);
}

Accordion.Item = function AccordionItem({
id,
title,
children,
}: {
id: string;
title: string;
children: ReactNode;
}) {
const { openItems, toggle } = useAccordion();
const isOpen = openItems.has(id);

return (
<div>
<button onClick={() => toggle(id)} className="w-full text-left py-3">
{title}
</button>
{isOpen && <div className="pb-3">{children}</div>}
</div>
);
};


### Vue 3: Composables

<script setup lang="ts">
import { ref, computed, provide, inject, type InjectionKey } from "vue";

interface TabsContext {
activeTab: Ref<string>;
setActive: (id: string) => void;
}

const TabsKey: InjectionKey<TabsContext> = Symbol("tabs");

// Parent component
const activeTab = ref("tab-1");
provide(TabsKey, {
activeTab,
setActive: (id: string) => {
activeTab.value = id;
},
});

// Child component usage
const tabs = inject(TabsKey);
const isActive = computed(() => tabs?.activeTab.value === props.id);
</script>


### Svelte 5: Runes

<script lang="ts">
interface Props {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
onclick?: () => void;
children: import('svelte').Snippet;
}

let { variant = 'primary', size = 'md', onclick, children }: Props = $props();

const classes = $derived(
btn btn-${variant} btn-${size}
);
</script>

<button class={classes} {onclick}>
{@render children()}
</button>


## Best Practices

1. **Single Responsibility**: Each component does one thing well
2. **Prop Drilling Prevention**: Use context for deeply nested data
3. **Accessible by Default**: Include ARIA attributes, keyboard support
4. **Controlled vs Uncontrolled**: Support both patterns when appropriate
5. **Forward Refs**: Allow parent access to DOM nodes
6. **Memoization**: Use React.memo, useMemo for expensive renders
7. **Error Boundaries**: Wrap components that may fail

## Common Issues

- **Prop Explosion**: Too many props - consider composition instead
- **Style Conflicts**: Use scoped styles or CSS Modules
- **Re-render Cascades**: Profile with React DevTools, memo appropriately
- **Accessibility Gaps**: Test with screen readers and keyboard navigation
- **Bundle Size**: Tree-shake unused component variants

## Resources

- [React Component Patterns](https://reactpatterns.com/)
- [Vue Composition API Guide](https://vuejs.org/guide/reusability/composables.html)
- [Svelte Component Documentation](https://svelte.dev/docs/svelte-components)
- [Radix UI Primitives](https://www.radix-ui.com/primitives)
- [shadcn/ui Components](https://ui.shadcn.com/)

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/web-component-design/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/wshobson/agents/web-component-design/SKILL.md
  • Cursor: ~/.cursor/skills/wshobson/agents/web-component-design/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/wshobson/agents/web-component-design/SKILL.md

🚀 Install with CLI:
npx skills add wshobson/agents

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid ui/ux design issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under UI/UX Design and is published by W. Shobson, maintained in wshobson/agents.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.