CC '26
All Chapters

PART III: PRODUCTION & TOOL LANDSCAPE · SECTION 09

From Design to Production

The capstone: take a design concept through to production-ready code

Reading time

17 min

From Design to Production

The capstone: take a design concept through to production-ready code

You have the skills. Prompting patterns from Chapter 4, CLAUDE.md from Chapter 5, design systems from Chapter 6, automation from Chapter 7, tool integrations from Chapter 8. This chapter puts them all together. You will follow a single design project — a SaaS pricing page — from blank folder to deployed site. Every technique in the book shows up here, in sequence, for real.

Production readiness contract

Do not ship because the page looks good in one browser. Ship only after build, tests, responsive screenshots, keyboard navigation, accessibility checks, performance budget, data/privacy review, security review, owner approval, and rollback path are all accounted for. Claude Code can help run these checks, but a human remains responsible for the release decision.

Define
Explore
Prototype
Refine
Harden
Ship

Think of this pipeline like the design process you already know: research, wireframe, visual design, refine with feedback, hand off for build, launch. Each stage maps to specific Claude Code techniques. You can pause between any stage and resume later.

9.1 Design-to-Production Pipeline

Design-to-Production Pipeline

The full pipeline has six stages. Each has a goal, a Claude Code technique, and a chapter in this book that teaches it in depth.

Stage Goal Claude Code Technique Learned In
1. Define State the design problem clearly Natural-language design brief in plan mode Ch 3 — Design intent
2. Explore Understand constraints and options Plan mode file exploration + reference analysis Ch 4 — Prompting
3. Prototype First working version Implementation from plan with CLAUDE.md Ch 3 + Ch 5
4. Refine Match design intent Chrome extension visual verification + iteration Ch 8 — Browser testing
5. Harden Production quality Accessibility audit, responsive fixes, hooks Ch 6 + Ch 7
6. Ship Deploy to users Tests, commit, PR, deploy pipeline Ch 7 — CI integration

This pipeline works for any size project. A single landing page might move through all six stages in one session. A full product might take weeks, with separate sessions for each stage. The structure stays the same.

Break between stages

Long sessions accumulate context that degrades output quality. I recommend running /clear between stages and resuming with --continue. The plan and CLAUDE.md carry forward; the accumulated noise does not.

9.2 Choosing Your Tech Stack

Choosing Your Tech Stack

Claude Code is stack-agnostic. It works with whatever frameworks your project uses. For designers moving to production, three stacks cover most cases.

Stack Best For Deploy Target Claude Knowledge
Next.js + Tailwind Production sites, marketing pages, dashboards Vercel (zero-config) Deep — conventions, App Router, SSR
Vite + React + Tailwind SPAs, component libraries, rapid prototyping Any static host Strong — standard patterns
Static HTML + CSS Landing pages, email templates, simple sites Anywhere Excellent — no framework conventions

For this capstone, I am using Next.js with Tailwind CSS. It is the most common production stack, and Claude Code has deep knowledge of Next.js conventions — the App Router, file-based routing, server components, and image optimization.

Scaffolding the project

Start Claude Code in the folder where you want the project to live. Ask it to scaffold everything.

Create a new Next.js 15 project with TypeScript and Tailwind CSS v4.
Use the App Router. Set up:
- src/app/ for pages
- src/components/ui/ for design system primitives
- src/components/ for composed components
- src/lib/ for utilities

Configure a CLAUDE.md with:
- Inter as the primary font
- Primary color: #6366f1 (indigo)
- Secondary color: #ec4899 (pink)
- Neutral: slate gray scale
- 2-space indentation, PascalCase components, kebab-case files
- Run typecheck and lint before committing

Claude generates the full project structure, configures Tailwind, writes the CLAUDE.md, and sets up the initial page. The CLAUDE.md ensures every future session starts with the same design language — the tokens, naming, and conventions from Chapter 5.

# CLAUDE.md (generated)

## Tech Stack
- Next.js 15 with App Router, TypeScript strict, Tailwind CSS v4

## Design Tokens
- Font: Inter (headings 700, body 400)
- Colors:
  - primary: #6366f1
  - secondary: #ec4899
  - neutral: slate-50 through slate-900
- Spacing: Tailwind default scale (4px base unit)
- Border radius: 8px cards, 6px buttons, full for avatars

## Code Style
- 2-space indentation
- Components: PascalCase, kebab-case files
- Use CVA for variant management
- Forward refs on all primitives
- ARIA attributes on interactive elements

## Workflow
- Run `npm run typecheck` after changes
- Run `npm run lint` before committing
- Start dev server: `npm run dev` (port 3000)

My Take

Plan mode is the most underused feature for design projects. Spending 10 minutes exploring before coding saves hours of iteration. Without exploration, Claude builds the first thing that comes to mind. With exploration, Claude builds the right thing. For small, well-defined tasks, skip planning and go straight to implementation. For anything with more than two components, plan first.

9.3 Building the Component Library

Building the Component Library

With the project scaffolded and CLAUDE.md in place, you build the design system primitives first. These are the building blocks every page section will use.

Three approaches to component generation

Claude Code can build components from a screenshot, from design tokens, or by following existing patterns in your codebase. The pattern-based approach produces the most consistent, production-ready output.

Pattern-based (recommended)

Look at @src/components/ui/Button.tsx to understand our
component patterns. Follow that pattern to build a Card
component with:
- Variant prop: elevated, outlined, filled
- Padding prop: sm, md, lg
- Slots for header, body, and footer
- Support for loading state

Screenshot-only (less consistent)

[paste screenshot]
Build this card component.

The pattern-based approach references an existing component so Claude matches your conventions — file structure, export style, prop naming, and TypeScript patterns. The screenshot approach works for one-off components but produces inconsistent code across a library.

Generating the full primitive set

Ask Claude to build all the primitives your pricing page needs in one prompt.

Build the following primitives in src/components/ui/.
Follow the Button.tsx pattern for structure, naming, and exports.

1. Card — composed with CardHeader, CardBody, CardFooter
   - Variants: elevated, outlined, filled
   - Padding: sm (12px), md (16px), lg (24px)

2. Badge — color variants (primary, secondary, neutral, success, warning)
   - Optional dot indicator
   - Sizes: sm, md

3. Avatar — image with fallback initials
   - Sizes: sm (32px), md (40px), lg (56px)
   - Group layout support (overlapping avatars)

4. PriceCard — specialized card for pricing tiers
   - Props: tier name, price, period, features list, CTA text, highlighted
   - Highlighted variant gets a ring and "Recommended" badge

Each component must:
- Accept className for overrides
- Forward refs with forwardRef
- Include TypeScript types
- Be fully accessible (ARIA, keyboard navigation)

Claude generates all four components. Because CLAUDE.md specifies design tokens and the Button.tsx reference establishes conventions, the output is consistent without you re-explaining anything.

A production component: the accessible Dialog

As an example of what production-ready looks like, here is the Dialog component Claude generates when you specify accessibility requirements.

import { useRef, useEffect } from "react";
import { createPortal } from "react-dom";

interface DialogProps {
  isOpen: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
}

export function Dialog({ isOpen, onClose, title, children }: DialogProps) {
  const dialogRef = useRef<HTMLDivElement>(null);
  const previousFocusRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (isOpen) {
      previousFocusRef.current = document.activeElement as HTMLElement;
      dialogRef.current?.focus();
    } else {
      previousFocusRef.current?.focus();
    }
  }, [isOpen]);

  useEffect(() => {
    if (!isOpen) return;
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape") onClose();
      if (e.key === "Tab") {
        const focusable = dialogRef.current?.querySelectorAll(
          'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
        );
        if (!focusable?.length) return;
        const first = focusable[0] as HTMLElement;
        const last = focusable[focusable.length - 1] as HTMLElement;
        if (e.shiftKey && document.activeElement === first) {
          e.preventDefault();
          last.focus();
        } else if (!e.shiftKey && document.activeElement === last) {
          e.preventDefault();
          first.focus();
        }
      }
    };
    document.addEventListener("keydown", handleKeyDown);
    return () => document.removeEventListener("keydown", handleKeyDown);
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return createPortal(
    <div
      role="dialog"
      aria-modal="true"
      aria-labelledby="dialog-title"
      className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
      onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
    >
      <div
        ref={dialogRef}
        tabIndex={-1}
        className="bg-white rounded-lg p-6 max-w-md w-full mx-4 shadow-xl"
      >
        <h2 id="dialog-title" className="text-lg font-semibold mb-4">
          {title}
        </h2>
        {children}
      </div>
    </div>,
    document.body
  );
}

This component traps focus inside the dialog, returns focus to the trigger when closed, responds to the Escape key, and uses proper ARIA attributes. You did not write any of this. You described what you needed, and Claude built it.

Tip

When you specify accessibility requirements in your component prompt, Claude includes them by default. When you do not specify them, Claude sometimes skips them. Always include accessibility requirements in your component briefs.

9.4 Responsive Design and Accessibility

Responsive Design and Accessibility

The prototype works on your screen. Now make it work on every screen and for every user.

Responsive design with specific breakpoints

Claude generates responsive layouts when you give it concrete breakpoint requirements. Vague instructions produce generic results. Specific instructions produce layouts that match your design intent.

Build the pricing page layout with these breakpoints:
- Mobile (<640px): single column, stacked cards, full-width CTA
- Tablet (640-1024px): 2-column grid for pricing cards
- Desktop (>1024px): 3-column grid with sidebar for FAQ

The navigation should collapse to a hamburger on mobile.
The feature comparison table should scroll horizontally on mobile.
Use Tailwind responsive prefixes (sm:, md:, lg:).

Claude applies these breakpoints across all components. Because the design tokens are defined in CLAUDE.md, the spacing, font sizes, and colors stay consistent across every breakpoint.

Accessibility as a prompt requirement

The same specificity principle applies to accessibility. Telling Claude to "make it accessible" produces partial results. Listing specific requirements produces thorough ones.

Review the pricing page for accessibility:
1. All images have alt text
2. Form labels are associated with inputs via htmlFor
3. Color contrast meets WCAG 2.1 AA (4.5:1 for body text)
4. All interactive elements are reachable via Tab
5. The pricing cards have role="group" with aria-label
6. The FAQ accordion uses aria-expanded and aria-controls
7. Focus indicators are visible (not outline:none)
8. The page has a logical heading hierarchy (h1, h2, h3)

Fix any issues you find.

Chrome extension for visual verification

The Chrome integration closes the feedback loop. You build something, Claude opens it in the browser, compares it to your design reference, and tells you what needs fixing.

claude --chrome
Open localhost:3000 in Chrome and verify:
1. The page matches the original design mockup I pasted
2. All sections render correctly on mobile (375px) and desktop (1440px)
3. No console errors
4. Tab navigation works through all interactive elements
5. Color contrast meets WCAG AA standards

Take a screenshot and tell me what needs fixing.

Claude reads the console, inspects the DOM, takes a screenshot, and compares it to your reference. It returns a list of visual differences — wrong spacing, misaligned elements, missing styles — and fixes them.

Warning

Code that looks correct in your editor can render differently in the browser. CSS specificity conflicts, missing imports, and responsive breakpoints do not show up in the code. They show up when you open the page. Always verify visually. The Chrome extension exists for this reason.

9.5 Testing and QA

Testing and QA

The prototype looks right. Now verify it behaves right — across states, screen sizes, and interactions.

Test generation that follows your patterns

Claude examines your existing test files to match the framework, assertion style, and structure your project uses. You do not need to specify which testing library to use — Claude reads your package.json and follows what is already there.

Write tests for the PriceCard component. Cover:
- Rendering with default props
- Rendering in highlighted state
- CTA button click fires the onClick handler
- Feature list renders all items
- Badge appears on highlighted card
- Responsive layout on mobile viewport

Run the tests and fix any failures.

Claude generates the test file, runs it, and fixes any failures. Here is what the output looks like when the project uses vitest.

import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { PriceCard } from "./PriceCard";

describe("PriceCard", () => {
  const defaultProps = {
    tier: "Pro",
    price: "$29",
    period: "/month",
    features: ["Unlimited projects", "Priority support", "API access"],
    ctaText: "Get Started",
    highlighted: false,
  };

  it("renders tier name and price", () => {
    render(<PriceCard {...defaultProps} />);
    expect(screen.getByText("Pro")).toBeInTheDocument();
    expect(screen.getByText("$29")).toBeInTheDocument();
  });

  it("shows badge when highlighted", () => {
    render(<PriceCard {...defaultProps} highlighted />);
    expect(screen.getByText("Recommended")).toBeInTheDocument();
  });

  it("fires onClick when CTA is clicked", () => {
    const onClick = vi.fn();
    render(<PriceCard {...defaultProps} onCtaClick={onClick} />);
    fireEvent.click(screen.getByText("Get Started"));
    expect(onClick).toHaveBeenCalledOnce();
  });

  it("renders all features", () => {
    render(<PriceCard {...defaultProps} />);
    expect(screen.getByText("Unlimited projects")).toBeInTheDocument();
    expect(screen.getByText("Priority support")).toBeInTheDocument();
    expect(screen.getByText("API access")).toBeInTheDocument();
  });
});

Verification-first prompting

The single highest-leverage technique for quality is giving Claude a way to verify its own work. The best practices documentation emphasizes this repeatedly. Compare two approaches.

Verification-first prompt

Implement the FAQ accordion component.
After implementing:
1. Run the component tests
2. Open localhost:3000 in Chrome
3. Verify keyboard navigation works
   (Tab between items, Enter to expand)
4. Check that aria-expanded toggles correctly
5. Screenshot the result

Fix anything that fails.

Implementation-only prompt

Implement the FAQ accordion component.

The verification-first prompt produces fewer bugs because Claude checks its own work immediately. When it finds a problem, it fixes it before showing you the result.

Hooks for automatic quality gates

Hooks guarantee that quality checks run after every change. Unlike CLAUDE.md instructions (advisory — Claude might ignore them), hooks are deterministic — they run every time without exception.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx eslint ${tool_input.file_path} --fix"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npm run typecheck && npm run lint && npm test"
          }
        ]
      }
    ]
  }
}

This hook configuration runs ESLint auto-fix after every file write or edit, and runs typecheck + lint + tests before completing any session. If any check fails, the session does not end clean — Claude keeps working until everything passes.

9.6 Deploying

Deploying

The code works locally. The tests pass. Time to put it on the internet.

The full deploy checklist

Before deploying, run through this checklist. Each item is a prompt you give Claude.

Category Check How to Verify
Tests All tests pass npm test
Types No TypeScript errors npm run typecheck
Lint No lint errors npm run lint
Build Production build succeeds npm run build
Responsive Works on mobile, tablet, desktop Chrome extension at 375px, 768px, 1440px
Accessibility Tab navigation, contrast, ARIA Manual Tab-through + Chrome DevTools audit
Console No errors or warnings Chrome extension reads console
Visual Matches design mockup Screenshot comparison with reference

Claude can run this entire checklist in a single prompt.

Run the full pre-deploy checklist:
1. Run all tests — fix failures
2. Run typecheck — fix errors
3. Run lint — fix issues
4. Run production build — fix errors
5. Open localhost:3000 in Chrome
6. Check responsive at 375px, 768px, 1440px
7. Tab through all interactive elements
8. Check console for errors
9. Take a screenshot and compare to the design mockup

Fix anything that fails. Then commit with:
"feat: pricing page — three tiers, comparison table, FAQ accordion"

Deploying to Vercel

For a Next.js project, Vercel is the default deployment target. The connection is native — push to main, the site updates.

Commit all changes and push to the main branch.
Vercel is connected to this repo and will auto-deploy.

After deployment completes, open the live URL in Chrome and:
1. Check for console errors
2. Verify all images load
3. Test the responsive layout on mobile
4. Take a screenshot and compare to the design mockup

Deploying as a static demo

For sharing a design without a server — a client review, a design critique, a portfolio piece — ask Claude to build a self-contained HTML file.

Build the pricing page as a single self-contained HTML file
that works offline when opened by double-clicking. Bundle all
CSS and JS inline. The file should work with no server.

GitHub Actions for continuous quality

For team projects, every pull request gets an automated review. Claude Code runs as a GitHub Action that checks accessibility, responsive design, and component consistency.

name: Design Review
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: |
            Review this PR for:
            - Accessibility issues (missing ARIA, poor contrast)
            - Responsive design problems
            - Component consistency with the design system
            - Performance concerns (large bundles, unnecessary re-renders)

Every PR now gets a design-oriented review before merge. This catches regressions that manual review misses — a color token swapped for a hardcoded value, a missing aria-label, a responsive breakpoint that broke during refactoring.

My Take

The biggest mistake designers make with AI coding tools is stopping at the prototype stage. The jump from prototype to production is where the real value is. Anyone can generate a prototype. Production-quality code that handles edge cases, accessibility, and responsive design is what separates experiments from shipped products. Not every project needs production quality — prototypes for user testing are valuable on their own. But if you are putting something on the internet with your name on it, take the time to harden it.

You started with a blank folder. You now have a pricing page built on a design system, tested, accessible, responsive, and deployed. Every technique came from a previous chapter. The pipeline is repeatable — define, explore, prototype, refine, harden, ship — for any project, any size, any stack. This is the workflow the book has been building toward. Everything else is practice.

Next Chapter

The AI Design Tool Landscape

Claude Code vs Cursor, Copilot, v0, Bolt, and the rest

Continue Reading

©2026 Mehran Mozaffari. All rights reserved.