ASD

Web Component Design

Domina patrones de componentes en React, Vue y Svelte: CSS-in-JS, estrategias de composición y arquitectura de componentes reutilizables para design systems.

Estrellas
38.8k

en todo el repo

Actividad
34

0–100, la ruta de este skill

Actualizado
hace 5 meses

último commit aquí

Commits
0

últimos 90 días

Contexto
1.9k tok

60 tok en reposo

Paquete
4 archivos

45 KB

Instalar

Funciona con cualquier agente que lea SKILL.md

npx -y skills add wshobson/agents --skill web-component-design --agent claude-code

Se instala solo en este repositorio.

Qué hace

  • Aplica patrones de composición de componentes: compound components, render props y slots
  • Define enfoques CSS-in-JS (Tailwind, CSS Modules, styled-components, Emotion, Vanilla Extract)
  • Diseña APIs de componentes con props semánticas y valores por defecto sensatos
  • Genera ejemplos de código para React, Vue 3 y Svelte 5

Úsalo cuando

  • Diseñar librerías de componentes reutilizables o sistemas de diseño
  • Implementar patrones complejos de composición de componentes
  • Elegir y aplicar una solución CSS-in-JS
  • Refactorizar componentes legacy hacia patrones modernos

No lo uses cuando

    Qué lo activa

    Di cualquiera de estas frases y el agente debería cargar este skill.

    • Ayúdame a diseñar un componente Accordion con compound components en React
    • Necesito elegir entre Tailwind y styled-components para mi design system
    • Crea un Button reutilizable con variantes usando class-variance-authority
    • Cómo implemento slots con nombre en Vue 3

    SKILL.md

    En inglés

    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

    Reproducido de wshobson/agents bajo licencia MIT. Leer esta página en markdown.

    Archivos

    4 archivos en el paquete. Solo se lee SKILL.md al activarse — las referencias se cargan si el skill decide que las necesita.

    Detalles

    Creador
    wshobson
    Categoría
    Diseño y UI
    Licencia
    MIT
    Recursos incluidos
    referencias
    Repositorio
    wshobson/agents
    Código fuente
    Ver SKILL.md

    Etiquetas

    Más de wshobson/agents

    Este repo incluye 180 skills. Si instalas uno, normalmente ya tienes los demás.

    Úsalo al seleccionar y colocar iconos, imágenes, SVGs, diagramas o infografías de apoyo aprobados en un PPTX editable.

    Costo de contexto al activarse
    344 tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 26 días
    documentos

    Úsalo cuando pidan optimizar un prompt, mejorar su rendimiento, diseñar una plantilla, aplicar chain-of-thought, few-shot prompting o técnicas avanzadas de prompt engineering para producción.

    Costo de contexto al activarse
    1.3k tok
    Tamaño del paquete
    10 archivos
    Última actualización
    el mes pasado
    herramientas desarrollo

    Úsalo al redactar o reparar una especificación JSON con coordenadas explícitas para un PPTX editable.

    Costo de contexto al activarse
    489 tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 26 días
    documentos

    Úsalo para validar o reparar un PPTX editable en cuanto a geometría, accesibilidad, editabilidad nativa, linaje de fuente e integridad del paquete OOXML.

    Costo de contexto al activarse
    409 tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 26 días
    documentos

    Úsalo para analizar un PPTX de referencia en modo solo lectura: estructura, tema, tipografía, ritmo de layout, diagnósticos, catálogos de plantillas derivados o inspección segura del paquete OOXML.

    Costo de contexto al activarse
    689 tok
    Tamaño del paquete
    8 archivos
    Última actualización
    hace 26 días
    documentos

    Úsalo al preparar la narrativa, las fuentes y el contexto de diseño para un nuevo deck PPTX editable.

    Costo de contexto al activarse
    415 tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 26 días
    documentos

    Skills relacionados

    Úsalo al hacer cambios de UI/frontend guiados por contexto visual: selecciones de elementos, anotaciones o capturas de pantalla junto con la solicitud de cambio.

    Costo de contexto al activarse
    547 tok
    Tamaño del paquete
    1 archivo
    Última actualización
    el mes pasado
    diseno ui

    Diseñador de landing pages centrado en marca: hace una entrevista de identidad visual y luego genera e itera la página con Stitch, entregando HTML listo para desplegar.

    Costo de contexto al activarse
    3.9k tok
    Tamaño del paquete
    4 archivos
    Última actualización
    hace 2 meses
    diseno ui

    Testea contratos inteligentes de forma exhaustiva con Hardhat y Foundry: tests unitarios, de integración y forking de mainnet.

    Costo de contexto al activarse
    2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 2 meses
    testing qa