R
Interview Deckreact · next.js · senior/staff
0·0·122
Design System

Componentização Avançada

Atomic Design, componentes compostos, API de componentes limpa e variantes com CVA.

Componentização eficaz segue princípios: Single Responsibility (um componente, uma responsabilidade), Open/Closed (extensível sem modificar), e interface mínima (poucas props obrigatórias). Atomic Design organiza componentes em Atoms (Button, Input), Molecules (FormField = Label + Input + Error), Organisms (LoginForm), Templates, e Pages. CVA (class-variance-authority) gerencia variantes sem if/else.

Problema
Componentes com 30 props booleanas (isLarge, isSmall, isPrimary, isSecondary, isDanger...). Props que mudam comportamento de forma imprevisível. Impossível entender o componente sem ler todo o código.
Solução
Variantes como strings (variant="primary" | "secondary" | "danger") em vez de booleanos. Compound components para composição flexível. CVA para gerenciar classes de variantes. Slots/children para extensibilidade sem proliferação de props.
Tip
A API de um componente é seu contrato com o consumidor. Adicionar prop é fácil; remover é breaking change. Prefira interface mínima — se não tem caso de uso claro, não adicione a prop. "You can always add, never remove."
// CVA para variantes sem if/else
import { cva, type VariantProps } from 'class-variance-authority'

const button = cva(
  'inline-flex items-center font-medium rounded transition-colors focus:outline-none focus:ring-2',
  {
    variants: {
      variant: {
        primary:   'bg-blue-600 text-white hover:bg-blue-700',
        secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
        danger:    'bg-red-600 text-white hover:bg-red-700',
        ghost:     'text-gray-600 hover:bg-gray-100',
      },
      size: {
        sm: 'text-xs px-2 py-1',
        md: 'text-sm px-3 py-2',
        lg: 'text-base px-4 py-3',
      },
    },
    defaultVariants: { variant: 'primary', size: 'md' },
  }
)

interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof button> {}

export function Button({ variant, size, className, ...props }: ButtonProps) {
  return <button className={button({ variant, size, className })} {...props} />
}

// Uso
<Button variant="danger" size="lg">Deletar</Button>
<Button variant="ghost">Cancelar</Button>
Q.Booleano vs string para variantes de componente?
A.String é melhor: variant="primary" | "secondary" é auto-documentável, mutuamente exclusivo por definição, e extensível sem breaking change. Booleanos (isPrimary, isSecondary) podem ser combinados de formas inválidas e ficam verbosos com muitas variantes.
Q.O que é o padrão de Compound Components?
A.Componentes que cooperam via Context implícito: <Select><Select.Trigger/><Select.Content><Select.Item/></Select.Content></Select>. O pai gerencia estado, filhos consomem via useContext. Radix UI, shadcn/ui e Headless UI usam esse padrão extensivamente.
Q.Como documentar componentes efetivamente?
A.Storybook com stories para cada variante e estado (default, hover, focus, disabled, error, loading). Controls para props interativas. Docs automáticos via JSDoc/TSDoc. Testes de acessibilidade com @storybook/addon-a11y. Stories servem como spec executável.
62/122← →