Skip to content

Component Library

Guidelines for using and creating components.

Design System

Colors

The design system uses CSS custom properties:

--primary: #31a8b6;      /* Freeze Design teal */
--primary-dark: #2a919d;
--primary-light: #b1e0e8;
--accent: #f87171;       /* Call-to-action red */
--foreground: #131117;   /* Dark text */
--muted-foreground: #525960;

Typography

--text-sm: 0.875rem;     /* 14px */
--text-base: 1rem;       /* 16px */
--text-lg: 1.125rem;     /* 18px */
--font-semibold: 600;
--font-bold: 700;

Spacing

--space-2: 0.5rem;       /* 8px */
--space-4: 1rem;         /* 16px */
--space-6: 1.5rem;       /* 24px */

Component Patterns

Props Interface

Always define typed props:

interface ComponentProps {
  /** Primary content */
  children: React.ReactNode;
  /** Visual variant */
  variant?: 'primary' | 'secondary';
  /** Additional CSS classes */
  className?: string;
}

Default Props

Use destructuring for defaults:

export function Component({
  variant = 'primary',
  className = '',
  children,
}: ComponentProps) {
  // ...
}

Composition

Prefer composition over configuration:

// Good
<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>Content</CardContent>
</Card>

// Avoid
<Card
  title="Title"
  content="Content"
  showHeader={true}
/>

Creating Stories

Every component should have a story:

// Component.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Component } from './Component';

const meta: Meta<typeof Component> = {
  title: 'Components/Category/Component',
  component: Component,
  tags: ['autodocs'],
};

export default meta;
type Story = StoryObj<typeof Component>;

export const Default: Story = {
  args: {
    children: 'Example',
  },
};

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

Accessibility

All components must:

  1. Support keyboard navigation
  2. Have appropriate ARIA attributes
  3. Meet WCAG 2.1 AA contrast ratios
  4. Include data-testid for testing
<button
  aria-label="Increase quantity"
  data-testid="quantity-increment"
>
  +
</button>