Skip to content

Instantly share code, notes, and snippets.

@adrianricardo
Created May 6, 2026 18:25
Show Gist options
  • Select an option

  • Save adrianricardo/c5599a1be8baa6c9ec1be34d72df21a1 to your computer and use it in GitHub Desktop.

Select an option

Save adrianricardo/c5599a1be8baa6c9ec1be34d72df21a1 to your computer and use it in GitHub Desktop.
Design foundation snippet for new Next.js + Tailwind + shadcn/ui projects. Paste into your spec before the first build so the design system is set up correctly from day one — no retrofit later.

Design Foundation (Before First Feature)

A spec snippet for new Next.js + Tailwind + shadcn/ui projects. Paste into your spec before the first build so the design system is set up correctly from the start — no retrofit later.

Prerequisite: a style reference doc at the project root (e.g. design.md) with tokens, typography, surfaces, components, and do/don'ts. The reference is the source of truth for visual direction; this foundation is its shadcn/Tailwind implementation. If no reference exists yet, generate one first.

Before writing any page or component code, run the foundation. One session, one commit.

1. Import tokens, then map brand → shadcn

Paste the reference's Quick Start CSS (Tailwind v4 block if present) into globals.css. Then map brand-specific names onto shadcn's semantic names so the primitives work without per-call overrides:

:root {
  /* Brand tokens (from design.md) */
  --color-warm-canvas: #fbfaf9;
  --color-graphite: #474645;
  --color-midnight: #121212;
  --color-ember-orange: #ff3e00;
  /* …etc */

  /* Shadcn semantic mapping */
  --background: var(--color-warm-canvas);
  --foreground: var(--color-graphite);
  --primary: var(--color-midnight);
  --primary-foreground: #ffffff;
  --accent: var(--color-ember-orange);
  /* …etc */
}

This mapping is the highest-leverage decision in the session. Document each mapping inline.

2. Override shadcn primitive defaults to match the reference

For every component the reference defines (Primary CTA, Feature Card, Testimonial Card, etc.), modify the shadcn source under components/ui/ so its defaults match — not Tailwind overrides at the call site.

Example: if the reference says cards use an inset stone border (no CSS border, no drop shadow, box-shadow: ... inset), make that the Card default.

Audit at minimum before first use: Card, Button, Badge, Input, Select.

3. Layout primitives (only if 3+ uses AND non-obvious)

PageLayout, Section, Stack only if they encode non-obvious values from the reference (max-width, section gap, sanctioned gap scale). Don't wrap for the sake of wrapping — three repeated lines beat a premature abstraction.

4. Write src/DESIGN_SYSTEM.md

The project's implementation doc — derived from the reference, tells engineers/agents what to do with it:

  • Token mapping table: brand name → shadcn name → when to use
  • Component inventory: what's been built, with the brand vocabulary each implements
  • Sanctioned scales: spacing, radius, typography (mirror the reference, name what's allowed)
  • Anti-patterns: pull the reference's "Don't" list verbatim, add project rules (no raw Tailwind colors, no style={{ }})

design.md = visual direction. DESIGN_SYSTEM.md = implementation.

5. Add design rules to CLAUDE.md

~10 lines, reference both docs:

  • Visual direction → design.md. Implementation rules → src/DESIGN_SYSTEM.md.
  • Use semantic tokens (bg-card, text-foreground) — never raw Tailwind colors (bg-white, text-gray-500).
  • Fix wrong primitive defaults at the source (components/ui/), not at the call site.
  • New visual decision? Update design.md first, propagate to DESIGN_SYSTEM.md, then build. Never invent values inline.

6. Add ESLint rules

Catch in CI what review can't:

  • Disallow raw color utilities (bg-white, text-gray-*, text-slate-*, bg-zinc-*) and hex literals in JSX className
  • Disallow style={{ }} props (escape: // eslint-disable-next-line with justification)
  • Optional: disallow off-scale spacing if the reference defines a sanctioned scale

After this session: every feature is built against this foundation. New visual decision needed → update design.md, propagate to DESIGN_SYSTEM.md, then build. Never invent visual values inline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment