🚀 Oferta especial: 60% OFF no CrazyStack - Últimas vagas!Garantir vaga →
Design System

Guia Empresarial 2025 Design System com Shadcn/UI

Construa um Design System escalável e profissional usando Shadcn/UI. Tokens, componentes, documentação e governança para equipes grandes.

Design System Enterprise

com Shadcn/UI 2025 Design System Profissional

Crie um Design System que escala para centenas de desenvolvedores. Tokens consistentes, componentes reutilizáveis e documentação completa.

100+
Componentes
500+
Tokens
99%
Consistência
design-tokens.ts
// design-tokens.ts export const tokens = { colors: { primary: { 50: 'hsl(210, 100%, 98%)', 100: 'hsl(210, 100%, 95%)', 500: 'hsl(210, 100%, 50%)', 900: 'hsl(210, 100%, 15%)' }, semantic: { success: 'hsl(142, 76%, 36%)', warning: 'hsl(38, 92%, 50%)', error: 'hsl(0, 84%, 60%)' } }, spacing: { xs: '0.25rem', // 4px sm: '0.5rem', // 8px md: '1rem', // 16px lg: '1.5rem', // 24px xl: '2rem' // 32px }, typography: { fontFamily: { sans: ['Inter', 'system-ui', 'sans-serif'], mono: ['JetBrains Mono', 'monospace'] }, fontSize: { xs: ['0.75rem', { lineHeight: '1rem' }], sm: ['0.875rem', { lineHeight: '1.25rem' }], base: ['1rem', { lineHeight: '1.5rem' }], lg: ['1.125rem', { lineHeight: '1.75rem' }], xl: ['1.25rem', { lineHeight: '1.75rem' }] } } }

Por que Design System com Shadcn/UI?

Design Systems reduzem tempo de desenvolvimento em 40% e garantem consistência visual em toda aplicação. Shadcn/UI oferece a base perfeita para construir sistemas escaláveis.

Empresas que Usam Design Systems

Google (Material), Apple (Human Interface), Microsoft (Fluent), Shopify (Polaris), Atlassian (Design System). Todas as grandes empresas tech investem pesadamente em Design Systems para escalar desenvolvimento.

Consistência

UI/UX uniforme em todas as telas. Reduz decisões de design e acelera desenvolvimento.

Velocidade

Desenvolvimento 3x mais rápido com componentes pré-construídos e documentados.

Escalabilidade

Suporte para equipes grandes com governança clara e versionamento controlado.

Vantagens do Design System Por que investir em Design System

Consistência Visual

Identidade visual unificada em todos os produtos. Tokens de design garantem harmonia entre cores, tipografia e espaçamentos.

Produtividade Máxima

Desenvolvimento 40% mais rápido com componentes prontos. Designers e desenvolvedores trabalham com a mesma linguagem.

Manutenibilidade

Atualizações centralizadas propagam para toda aplicação. Um bugfix ou melhoria beneficia todos os produtos.

Governança Clara

Regras e padrões definidos para uso correto dos componentes. Documentação completa e exemplos práticos.

Escalabilidade

Suporte para equipes grandes com versionamento semântico e breaking changes controlados.

Developer Experience

TypeScript completo com IntelliSense, documentação inline e exemplos de uso em tempo real.

Fundamentos do Design System

Estrutura sólida para um Design System escalável. Tokens, componentes, padrões e documentação organizados de forma sistemática.

Por que Essa Estrutura é Importante

Design Systems bem estruturados reduzem debt técnico e facilitam onboarding de novos desenvolvedores. Organização clara resulta em adoção mais rápida e manutenção simplificada.

1Design Tokens

🎨 O que são Design Tokens:

Valores atômicos que definem o visual do sistema. Cores, espaçamentos, tipografia e outros elementos visuais centralizados.

Color Tokens:

Primary, secondary, semantic colors

Spacing Tokens:

Margins, paddings, gaps consistentes

Typography Tokens:

Font families, sizes, weights, line heights

💻 Implementação:

// tokens/colors.ts
export const colors = {
  // Brand colors
  brand: {
    primary: {
      50: 'hsl(210, 100%, 98%)',
      100: 'hsl(210, 100%, 95%)',
      200: 'hsl(210, 100%, 90%)',
      300: 'hsl(210, 100%, 80%)',
      400: 'hsl(210, 100%, 70%)',
      500: 'hsl(210, 100%, 50%)', // Base
      600: 'hsl(210, 100%, 45%)',
      700: 'hsl(210, 100%, 35%)',
      800: 'hsl(210, 100%, 25%)',
      900: 'hsl(210, 100%, 15%)',
      950: 'hsl(210, 100%, 8%)'
    }
  },
  
  // Semantic colors
  semantic: {
    success: {
      light: 'hsl(142, 76%, 45%)',
      DEFAULT: 'hsl(142, 76%, 36%)',
      dark: 'hsl(142, 76%, 25%)'
    },
    warning: {
      light: 'hsl(38, 92%, 60%)',
      DEFAULT: 'hsl(38, 92%, 50%)',
      dark: 'hsl(38, 92%, 40%)'
    },
    error: {
      light: 'hsl(0, 84%, 70%)',
      DEFAULT: 'hsl(0, 84%, 60%)',
      dark: 'hsl(0, 84%, 50%)'
    }
  },
  
  // Neutral colors
  neutral: {
    0: 'hsl(0, 0%, 100%)',
    50: 'hsl(210, 20%, 98%)',
    100: 'hsl(220, 14%, 96%)',
    200: 'hsl(220, 13%, 91%)',
    300: 'hsl(216, 12%, 84%)',
    400: 'hsl(218, 11%, 65%)',
    500: 'hsl(220, 9%, 46%)',
    600: 'hsl(215, 14%, 34%)',
    700: 'hsl(217, 19%, 27%)',
    800: 'hsl(215, 28%, 17%)',
    900: 'hsl(221, 39%, 11%)',
    950: 'hsl(224, 71%, 4%)',
    1000: 'hsl(0, 0%, 0%)'
  }
}

// tokens/spacing.ts
export const spacing = {
  0: '0px',
  px: '1px',
  0.5: '0.125rem',  // 2px
  1: '0.25rem',     // 4px
  1.5: '0.375rem',  // 6px
  2: '0.5rem',      // 8px
  2.5: '0.625rem',  // 10px
  3: '0.75rem',     // 12px
  3.5: '0.875rem',  // 14px
  4: '1rem',        // 16px
  5: '1.25rem',     // 20px
  6: '1.5rem',      // 24px
  7: '1.75rem',     // 28px
  8: '2rem',        // 32px
  9: '2.25rem',     // 36px
  10: '2.5rem',     // 40px
  11: '2.75rem',    // 44px
  12: '3rem',       // 48px
  14: '3.5rem',     // 56px
  16: '4rem',       // 64px
  20: '5rem',       // 80px
  24: '6rem',       // 96px
  28: '7rem',       // 112px
  32: '8rem',       // 128px
  36: '9rem',       // 144px
  40: '10rem',      // 160px
  44: '11rem',      // 176px
  48: '12rem',      // 192px
  52: '13rem',      // 208px
  56: '14rem',      // 224px
  60: '15rem',      // 240px
  64: '16rem',      // 256px
  72: '18rem',      // 288px
  80: '20rem',      // 320px
  96: '24rem'       // 384px
}

2Arquitetura de Componentes

🏗️ Hierarquia de Componentes:

Primitivos (Atoms):

Elementos básicos não decomponíveis

ButtonInputLabelIcon
Compostos (Molecules):

Combinação de primitivos

SearchBoxFormFieldCard
Organismos (Organisms):

Seções complexas da interface

HeaderSidebarDataTable

💻 Exemplo de Componente:

// components/ui/button.tsx
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'

// Variants usando CVA
const buttonVariants = cva(
  // Base classes
  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline"
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10"
      }
    },
    defaultVariants: {
      variant: "default",
      size: "default"
    }
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button"
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = "Button"

export { Button, buttonVariants }

3Padrões e Guidelines

📋 Padrões de Uso:

✅ Fazer:
  • • Use variants semânticas (primary, secondary)
  • • Mantenha hierarquia visual clara
  • • Siga padrões de acessibilidade
  • • Use tokens de design consistentemente
❌ Não fazer:
  • • Não customize cores diretamente
  • • Não misture padrões diferentes
  • • Não ignore estados de loading/error
  • • Não quebre a hierarquia visual

📖 Documentação:

/
 * Button Component
 * 
 * @description
 * Botão primário do sistema. Use para ações principais
 * como submit de formulários, CTAs e navegação.
 * 
 * @example
 * // Botão primário
 * <Button variant="default">Salvar</Button>
 * 
 * // Botão secundário
 * <Button variant="outline">Cancelar</Button>
 * 
 * // Botão com ícone
 * <Button size="icon">
 *   <PlusIcon className="h-4 w-4" />
 * </Button>
 * 
 * @accessibility
 * - Suporte completo a keyboard navigation
 * - ARIA labels automáticos
 * - Focus visible para screen readers
 * - Estados disabled acessíveis
 * 
 * @variants
 * - default: Ação primária (azul)
 * - destructive: Ações destrutivas (vermelho)
 * - outline: Ação secundária (borda)
 * - secondary: Ação terciária (cinza)
 * - ghost: Ação sutil (transparente)
 * - link: Ação de link (sublinhado)
 * 
 * @sizes
 * - default: 40px altura (padrão)
 * - sm: 36px altura (compacto)
 * - lg: 44px altura (destaque)
 * - icon: 40x40px (apenas ícone)
 */

Exemplos de Design System

Implementações reais de Design Systems usando Shadcn/UI. Veja como grandes empresas estruturam seus sistemas.

Casos de Sucesso

Vercel, Linear, Supabase e Cal.com usam Shadcn/UI como base para seus Design Systems. Aprenda com implementações que servem milhões de usuários diariamente.

Component Showcase

🎨 Variações de Botões:

Primary Actions:
Secondary Actions:
Destructive Actions:

💻 Código dos Botões:

// Uso dos botões no Design System
import { Button } from '@/components/ui/button'

// Primary actions
<Button variant="default">Save Changes</Button>
<Button variant="default" className="bg-green-600 hover:bg-green-700">
  Create New
</Button>
<Button variant="default" className="bg-purple-600 hover:bg-purple-700">
  Upgrade Plan
</Button>

// Secondary actions
<Button variant="outline">Cancel</Button>
<Button variant="outline">Learn More</Button>

// Destructive actions
<Button variant="destructive">Delete Account</Button>
<Button variant="outline" className="border-red-300 text-red-700 hover:bg-red-50">
  Remove Item
</Button>

// Sizes
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>

// With icons
<Button>
  <PlusIcon className="mr-2 h-4 w-4" />
  Add Item
</Button>

// Loading state
<Button disabled>
  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
  Loading...
</Button>

Form Components System

📝 Componentes de Formulário:

Input Fields:
Select & Checkbox:

💻 Form System Code:

// Form components com validação
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import * as z from 'zod'
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Checkbox } from '@/components/ui/checkbox'

const formSchema = z.object({
  email: z.string().email('Email inválido'),
  password: z.string().min(8, 'Mínimo 8 caracteres'),
  country: z.string().min(1, 'Selecione um país'),
  terms: z.boolean().refine(val => val === true, {
    message: 'Você deve aceitar os termos'
  })
})

export function SignupForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      email: '',
      password: '',
      country: '',
      terms: false
    }
  })
  
  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values)
  }
  
  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input placeholder="seu@email.com" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input type="password" placeholder="••••••••" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <FormField
          control={form.control}
          name="country"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Country</FormLabel>
              <Select onValueChange={field.onChange} defaultValue={field.value}>
                <FormControl>
                  <SelectTrigger>
                    <SelectValue placeholder="Select country" />
                  </SelectTrigger>
                </FormControl>
                <SelectContent>
                  <SelectItem value="br">Brazil</SelectItem>
                  <SelectItem value="us">United States</SelectItem>
                </SelectContent>
              </Select>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <FormField
          control={form.control}
          name="terms"
          render={({ field }) => (
            <FormItem className="flex flex-row items-start space-x-3 space-y-0">
              <FormControl>
                <Checkbox
                  checked={field.value}
                  onCheckedChange={field.onChange}
                />
              </FormControl>
              <div className="space-y-1 leading-none">
                <FormLabel>I agree to the terms</FormLabel>
              </div>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <Button type="submit" className="w-full">
          Create Account
        </Button>
      </form>
    </Form>
  )
}

Documentação e Storybook

Documentação viva e interativa para seu Design System. Storybook + Shadcn/UI para máxima produtividade da equipe.

Setup Storybook

📚 Instalação:

npx storybook@latest init

Storybook detecta automaticamente Next.js e configura tudo.

⚙️ Configuração:

// .storybook/main.ts
import type { StorybookConfig } from '@storybook/nextjs'

const config: StorybookConfig = {
  stories: ['../src//*.stories.@(js|jsx|ts|tsx|mdx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-a11y',
    '@storybook/addon-docs'
  ],
  framework: {
    name: '@storybook/nextjs',
    options: {}
  },
  typescript: {
    check: false,
    reactDocgen: 'react-docgen-typescript'
  }
}

export default config

🎨 Preview config:

// .storybook/preview.ts
import type { Preview } from '@storybook/react'
import '../src/app/globals.css'

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/
      }
    },
    docs: {
      toc: true
    }
  },
  globalTypes: {
    theme: {
      description: 'Global theme for components',
      defaultValue: 'light',
      toolbar: {
        title: 'Theme',
        icon: 'paintbrush',
        items: ['light', 'dark'],
        dynamicTitle: true
      }
    }
  }
}

export default preview

Stories Examples

📖 Button Stories:

// stories/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from '@/components/ui/button'
import { PlusIcon } from 'lucide-react'

const meta: Meta<typeof Button> = {
  title: 'UI/Button',
  component: Button,
  parameters: {
    layout: 'centered',
    docs: {
      description: {
        component: 'Botão primário do Design System. Use para ações principais como submit de formulários e CTAs.'
      }
    }
  },
  tags: ['autodocs'],
  argTypes: {
    variant: {
      control: { type: 'select' },
      options: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link']
    },
    size: {
      control: { type: 'select' },
      options: ['default', 'sm', 'lg', 'icon']
    },
    asChild: {
      control: { type: 'boolean' }
    }
  }
}

export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {
  args: {
    children: 'Button'
  }
}

export const Secondary: Story = {
  args: {
    variant: 'secondary',
    children: 'Secondary'
  }
}

export const Destructive: Story = {
  args: {
    variant: 'destructive',
    children: 'Delete'
  }
}

export const Outline: Story = {
  args: {
    variant: 'outline',
    children: 'Outline'
  }
}

export const WithIcon: Story = {
  args: {
    children: (
      <>
        <PlusIcon className="mr-2 h-4 w-4" />
        Add Item
      </>
    )
  }
}

export const Loading: Story = {
  args: {
    disabled: true,
    children: 'Loading...'
  }
}

export const AllSizes: Story = {
  render: () => (
    <div className="flex items-center gap-4">
      <Button size="sm">Small</Button>
      <Button size="default">Default</Button>
      <Button size="lg">Large</Button>
    </div>
  )
}

export const AllVariants: Story = {
  render: () => (
    <div className="flex flex-wrap gap-4">
      <Button variant="default">Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="link">Link</Button>
    </div>
  )
}

🚀 Executar Storybook:

npm run storybook

Acesse http://localhost:6006 para ver sua documentação interativa.

Pronto para criar seu Design System?

Comece agora e construa um sistema escalável