## Frontend Development Guide

When the task involves frontend development (React, Next.js, Vue), follow these patterns.

### Component Architecture

| File                                      | When          | Content                            |
| ----------------------------------------- | ------------- | ---------------------------------- |
| `{Name}.tsx`                              | Always        | Component with props interface     |
| `{Name}.module.css` or `{Name}.styles.ts` | Styled        | CSS modules or styled-components   |
| `{Name}.test.tsx`                         | Always        | Unit + integration tests           |
| `{Name}.stories.tsx`                      | Reusable      | Storybook stories for all variants |
| `use{Name}.ts`                            | Complex state | Custom hook for state/logic        |

### React Component Pattern

```tsx
// Props interface  -  explicit, documented
interface ButtonProps {
  label: string;
  variant?: "primary" | "secondary" | "ghost";
  size?: "sm" | "md" | "lg";
  disabled?: boolean;
  loading?: boolean;
  onClick: () => void;
}

// Component  -  single responsibility
export function Button({
  label,
  variant = "primary",
  size = "md",
  disabled = false,
  loading = false,
  onClick,
}: ButtonProps) {
  return (
    <button
      className={cn(styles.button, styles[variant], styles[size])}
      disabled={disabled || loading}
      onClick={onClick}
      aria-busy={loading}
    >
      {loading ? <Spinner size={size} /> : label}
    </button>
  );
}
```

### State Management

```tsx
// Simple state  -  useState/useReducer
const [count, setCount] = useState(0);

// Complex state  -  custom hook
function useAuth() {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    authService
      .getCurrentUser()
      .then(setUser)
      .finally(() => setLoading(false));
  }, []);

  return { user, loading, isAuthenticated: !!user };
}

// Server state  -  React Query / SWR
const { data, isLoading, error } = useQuery({
  queryKey: ["users", userId],
  queryFn: () => fetchUser(userId),
});
```

### Token Discipline

| Bad                | Good                                         |
| ------------------ | -------------------------------------------- |
| `padding: '16px'`  | `padding: tokens.spacing.md` or CSS variable |
| `color: '#E31837'` | `color: var(--color-primary)`                |
| `fontSize: '14px'` | `fontSize: tokens.typography.body.size`      |
| `"Submit"` inline  | `t('form.submit')` (i18n)                    |

### Accessibility

Every interactive element MUST have:

- Semantic HTML (`<button>`, `<nav>`, `<main>`, not `<div onClick>`)
- `aria-label` when visual label is absent
- `aria-describedby` for supplementary info
- Keyboard navigation support (focus management)
- Color contrast ratio >= 4.5:1

```tsx
<button aria-label="Close dialog" aria-describedby="dialog-description" onClick={onClose}>
  <CloseIcon aria-hidden="true" />
</button>
```

### Testing

```tsx
// Component test  -  React Testing Library
test("renders button with label", () => {
  render(<Button label="Submit" onClick={vi.fn()} />);
  expect(screen.getByRole("button", { name: "Submit" })).toBeInTheDocument();
});

test("calls onClick when clicked", async () => {
  const onClick = vi.fn();
  render(<Button label="Submit" onClick={onClick} />);
  await userEvent.click(screen.getByRole("button"));
  expect(onClick).toHaveBeenCalledOnce();
});

test("shows loading state", () => {
  render(<Button label="Submit" loading onClick={vi.fn()} />);
  expect(screen.getByRole("button")).toHaveAttribute("aria-busy", "true");
});
```

### Quality Checklist

1. No magic numbers  -  design tokens or CSS variables
2. Semantic HTML  -  correct elements, not div-soup
3. Accessibility  -  ARIA labels, keyboard nav, contrast
4. Responsive  -  works on mobile, tablet, desktop
5. i18n  -  all strings via translation keys
6. Error boundaries  -  graceful error handling
7. Loading states  -  skeleton/spinner for async operations
8. Tests  -  component + hook tests, no implementation details
9. Performance  -  memoization where needed (React.memo, useMemo, useCallback)
10. Build passes  -  zero warnings, TypeScript strict mode
