--- name: stitch-react-components description: Converts a Stitch screen, a local HTML file, or a URL into modular Vite + React components — TypeScript, theme-mapped Tailwind, dark mode via CSS variables, and clean component architecture. Use this for Vite/React apps without App Router. For Next.js 15 App Router, use stitch-nextjs-components instead. Only the Stitch route needs an API key. allowed-tools: - "stitch*:*" - "Bash" - "Read" - "Write" --- # Stitch → Vite / React Components **Constraint:** Only use this skill when the user explicitly mentions "Stitch" and React (Vite, CRA, or just "React app" without Next.js). You are a frontend engineer converting Stitch mobile/desktop designs into clean, modular React components using Vite + TypeScript. This skill targets plain React apps — **not** Next.js App Router. For Next.js, use `stitch-nextjs-components` instead. ## When to use this skill vs. Next.js | Scenario | Use | |----------|-----| | User says "React app", "Vite", "CRA" | `stitch-react-components` | | User says "Next.js", "App Router", "SSR" | `stitch-nextjs-components` | | User wants shadcn/ui components added after | `stitch-react-components` → then `stitch-shadcn-ui` | | User wants server-side rendering or file-based routing | `stitch-nextjs-components` | ## Prerequisites An HTML source. Any one of these works: - A **Stitch screen** — needs Stitch MCP access and a generated screen - A **local HTML file** — no Stitch account required - A **URL** — no Stitch account required Also: - Node.js + npm/pnpm - Vite + React project initialized: `npm create vite@latest my-app -- --template react-ts` ## Step 1: Resolve the source Everything downstream reads one file: `temp/source.html`. Get the HTML there by whichever route matches what the user gave you, then continue at Step 2 — the rest of this skill is identical regardless of where the markup came from. **From a Stitch screen:** 1. **Namespace discovery** — `list_tools` to find the Stitch MCP prefix 2. **Fetch metadata** — `[prefix]:get_screen` with numeric `projectId` and `screenId` 3. **Download HTML** — GCS URLs need the reliable downloader: ```bash bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html" ``` 4. **Visual audit** — check `screenshot.downloadUrl` before rewriting. Append `=s0` to that URL for full resolution; the bare URL serves a 512px thumbnail regardless of the `width`/`height` the API reports. **From a local HTML file:** ```bash mkdir -p temp && cp "path/to/design.html" temp/source.html ``` **From a URL:** ```bash bash scripts/fetch-stitch.sh "https://example.com/page" "temp/source.html" ``` Despite the name, that script is a generic hardened downloader — follows redirects, retries transient failures, handles gzip, and fails loudly on an empty result. It does not care whether the URL points at Stitch. **From a screenshot:** there's no upload route — the Stitch MCP API has no image-upload tool. Either recreate the design from a text prompt via `stitch-mcp-generate-screen-from-text`, or hand-write the HTML and use the local-file route above. > Only the Stitch route needs an API key. Converting a local file or a URL works with no Google account at all. ## Step 2: Project structure ``` src/ ├── components/ ← One file per component │ └── [Name].tsx ├── data/ │ └── mockData.ts ← Static content (never in components) ├── theme/ │ ├── tokens.ts ← Design token constants │ └── useTheme.ts ← Dark mode hook ├── types/ │ └── index.ts ← Shared TypeScript types ├── App.tsx ← Root component └── main.tsx ← Entry point ``` ## Step 3: Extract design tokens Resolve tokens from whatever the HTML actually gives you, in this order: 1. **Inline `tailwind.config`** in `` (what Stitch emits) — use it directly if present. 2. **CSS custom properties** (`:root { --color-primary: ... }`) — common in hand-written and templated HTML. 3. **A linked or inline stylesheet** — parse declared colors, font-families, radii, spacing. 4. **Last resort** — derive tokens from the most frequent computed values in the markup (dominant background, text color, accent, heading/body font, border radius), and tell the user what you inferred so they can correct it. The URL route only downloads the single HTML response — externally-linked stylesheets may not come along for the ride. If none of the above resolves a token, say so instead of inventing a palette. ```ts // src/theme/tokens.ts export const lightTokens = { background: '#FFFFFF', surface: '#F4F4F5', primary: '#6366F1', primaryFg: '#FFFFFF', text: '#09090B', textMuted: '#71717A', border: '#E4E4E7', } as const export const darkTokens = { background: '#09090B', surface: '#18181B', primary: '#818CF8', primaryFg: '#09090B', text: '#FAFAFA', textMuted: '#A1A1AA', border: '#27272A', } as const export type ThemeTokens = typeof lightTokens ``` ```ts // src/theme/useTheme.ts import { useEffect, useState } from 'react' import { lightTokens, darkTokens, type ThemeTokens } from './tokens' /** * Returns current theme tokens based on system color scheme. * Listens for system-level dark/light mode changes. */ export function useTheme(): ThemeTokens { const [isDark, setIsDark] = useState( () => window.matchMedia('(prefers-color-scheme: dark)').matches ) useEffect(() => { const mq = window.matchMedia('(prefers-color-scheme: dark)') const handler = (e: MediaQueryListEvent) => setIsDark(e.matches) mq.addEventListener('change', handler) return () => mq.removeEventListener('change', handler) }, []) return isDark ? darkTokens : lightTokens } ``` ## Step 4: Component conversion rules ### Layout mapping | HTML/CSS | → React / Tailwind | |---|---| | `display:flex; flex-direction:column` | `
` | | `display:flex; flex-direction:row` | `
` | | `justify-content:space-between` | `
` | | `display:grid; grid-template-columns:1fr 1fr` | `
` | | `overflow-y:scroll` | `
` | | Long list | `items.map(item => )` | | `` | `...` | ### Tailwind class mapping Use the source HTML's Tailwind classes directly in JSX where they don't reference custom tokens. Map custom tokens to CSS variables: ```tsx // Source HTML: bg-primary → CSS variable → Tailwind arbitrary value // OR: use inline style with token value // Option A — Tailwind arbitrary value (if custom tokens in tailwind.config)
// Option B — inline style with useTheme() const theme = useTheme()
``` ### Component template ```tsx // src/components/StitchComponent.tsx /** * Props for StitchComponent — all data via props, never fetched inside. */ interface StitchComponentProps { /** Primary heading text */ title: string /** Supporting description — optional */ description?: string /** Primary action callback */ onAction?: () => void } /** * StitchComponent — [describe purpose in one sentence] */ export function StitchComponent({ title, description, onAction, }: Readonly) { const theme = useTheme() return (

{title}

{description ? (

{description}

) : null} {onAction ? ( ) : null}
) } ``` ## Step 5: Architectural rules - **One component per file** — no single-file spaghetti - **Static data in `src/data/mockData.ts`** — never hardcoded in JSX - **Shared types in `src/types/index.ts`** - **Every component has `Readonly` interface** - **No hardcoded hex colors** — use `useTheme()` or CSS variables - **No `any` types** ## Step 6: Integration with shadcn/ui After converting the design to base React components, you can layer in shadcn/ui: ```bash npx shadcn@latest init # Set up shadcn in your Vite project npx shadcn@latest add button card input dialog ``` Then use `stitch-shadcn-ui` skill to replace raw HTML elements with shadcn components while preserving the design tokens. ## Troubleshooting | Issue | Fix | |-------|-----| | Tailwind classes not applying | Check `tailwind.config.js` includes `./src/**/*.{ts,tsx}` in content | | Dark mode not toggling | Verify `useTheme()` is called at component level, not hoisted | | Images not showing | Add explicit `width` and `height` or use `className="w-full h-auto"` | | Type error on props | Ensure `Readonly<>` wrapper and all required props are provided | ## References - `resources/component-template.tsx` — Boilerplate component - `resources/architecture-checklist.md` — Pre-ship checklist - `references/tailwind-to-react.md` — Token + class mapping guide (source HTML → React/Tailwind) - `scripts/fetch-stitch.sh` — Reliable GCS HTML downloader - `stitch-shadcn-ui` — Add shadcn/ui components after base conversion - `docs/tailwind-reference.md` — Tailwind utility class lookup