React 19 Component Scaffolder
Generate React 19/19.2 components, pages, hooks, and supporting files from parameterized templates. Every template enforces the patterns codified in the sibling react skill — refs as regular props (never forwardRef), Context rendered directly as provider (never .Provider), form actions with useActionState + useFormStatus, inline document metadata, useSyncExternalStore for external subscriptions, and YMNNAE-compliant hook bodies.
When to Apply
- Creating a new React component (Server, Client, or unspecified — defaults to Server)
- Adding a new route/page in a React 19 app
- Building a form that needs progressive enhancement, optimistic UI, or pending state
- Setting up a new Context provider with state + dispatch split
- Writing a custom hook that subscribes to external state or wraps async work
- Modeling complex state with a typed reducer
- Adding document metadata (
<title>, <meta>, <link>) or resource hints (preload, preconnect, prefetchDNS)
- The user says "scaffold", "boilerplate", "generate", "new component", "new page", "new hook", or names any of the template types
Available Templates
All filenames are kebab-case; the exported React identifier ({Name}, use{Name}) is PascalCase / camelCase.
| # |
Template |
When to use |
Files generated |
| 1 |
function-component |
Generic reusable component (works in Server or Client) |
{name-kebab}.tsx, {name-kebab}.test.tsx |
| 2 |
server-component-page |
Route page with server data fetch + Suspense + metadata |
page.tsx |
| 3 |
client-island |
'use client' interactivity nested inside a server page |
{name-kebab}-island.tsx, {name-kebab}-island.test.tsx |
| 4 |
form-action |
Mutation form with useActionState + Zod schema + server action |
{name-kebab}-form.tsx, actions.ts, schema.ts |
| 5 |
context-provider |
Shared state with state/dispatch split and accessor hook |
{name-kebab}-context.tsx |
| 6 |
custom-hook |
YMNNAE-compliant hook (external subscription or composed effect) |
use-{name-kebab}.ts, use-{name-kebab}.test.ts |
| 7 |
reducer |
Typed reducer with discriminated-union actions + exhaustive switch |
{name-kebab}-reducer.ts, {name-kebab}-reducer.test.ts |
| 8 |
head-and-hints |
Document metadata + resource hints for above-the-fold assets |
{name-kebab}-head.tsx |
How to Use
- Identify the template that matches the user's request. If ambiguous, ask. Default to
function-component for unqualified "make me a component" requests.
- Read the template at
assets/templates/{name}.template.
- Read the related conventions at
references/conventions.md — every template emits code that obeys these conventions.
- Collect parameters (see "Parameters" below). Ask the user only for parameters you cannot infer from context.
- Substitute placeholders in the template. Every placeholder is wrapped in
{curly_braces}. Empty placeholders (e.g., {additional_hooks} when there are none) collapse to empty string.
- Write each output file using the Write tool. Use the path conventions in
config.json (module_path, route_path).
- Mention the conventions enforced so the user understands why the generated code looks the way it does (e.g., "I used
ref as a prop rather than forwardRef because…").
Parameters
Common parameters (most templates accept these):
| Parameter |
Required |
Default |
Description |
name |
yes |
— |
Component / hook / reducer identifier in PascalCase (or camelCase for hooks/reducers). The scaffolder derives file_name (kebab-case) and name_kebab automatically. |
module_path |
no |
src/components (or from config.json) |
Directory under the project root for the generated files |
props |
no |
[] |
List of {name, type, required} — emitted as the props interface |
with_test |
no |
true |
Generate the matching *.test.tsx / *.test.ts file |
with_ref |
no |
false |
Add ref?: Ref<T> to props (templates 1 and 3) |
Template-specific parameters are documented in each template's leading comments.
Setup
On first use, populate config.json with project-specific paths so generated files land in the right place. The defaults assume a standard src/-rooted project. To override interactively:
module_path — Where components live (e.g., src/components, app/_components)
route_path — Where Server Component pages live (e.g., app/, src/routes/)
hooks_path — Where custom hooks live (e.g., src/hooks)
test_runner — vitest (default) or jest (changes the imports in test templates)
Conforming Existing Code (Multi-File Refactor)
When the user asks to conform, modernize, or align existing components with this skill's conventions across one or more files — not to generate new code — follow references/_conform-algorithm.md instead of going file-by-file.
Two non-negotiables from that doc:
- Judgment over grep. Every convention is keyed off a syntactic marker (
forwardRef, <Context.Provider>, react-helmet, onSubmit=, react-dom/test-utils). Grep finds the easy cases and misses the disguised ones — a manually drilled callback ref because the author dodged forwardRef, a bespoke useState({ pending, error }) that's useActionState without the name, a document.title hand-roll. Use grep for inventory and post-hoc completeness only, never as the primary detector.
- Convention-major, not file-major. Load all target files first, then sweep one convention at a time across all files in priority order (refs/context/forms first, naming/imports last). Reports group by convention, surfacing cross-file clusters.
For brand-new scaffolds, skip this — go straight to a template.
React 19 Patterns This Skill Refuses to Generate
forwardRef(...) wrappers — emits function Name({ ref, ...props }) instead
<Context.Provider value={...}> — emits <Context value={...}> instead
useFormState — emits useActionState instead
onSubmit handlers for mutations — emits <form action={serverAction}> instead
useRef<T>() without an argument — emits useRef<T>(null)
useEffect for derived state, parent notification, or POST-on-state-change — refuses entirely (see conventions: State derivation)
react-dom/test-utils — emits import { act } from '@testing-library/react' instead
- Manual
<link rel="preload"> JSX — emits preload() from react-dom instead
react-helmet / react-helmet-async — emits inline <title>/<meta>/<link> instead
Gotchas
See gotchas.md. Empty on first release — gotchas accumulate as the skill is used.
Related Skills
react — Authoritative React 19 best-practices distillation (44 rules). The templates in this skill emit code that conforms to those rules.
1---2name: react-19-component-scaffolder3description: Scaffolds React 19 / React 19.2 code in TypeScript — components, Server Component pages, client islands, form actions with useActionState, context providers, custom hooks, reducers, or document metadata + resource hints. Generates production-grade code that follows React 19 idioms (ref-as-prop, <Context value={...}>, useActionState, inline metadata, useSyncExternalStore) and refuses deprecated React 18 patterns (forwardRef, <Context.Provider>, useFormState, react-dom/test-utils). Trigger even when the user says "create a component", "new page", "add a form", "new hook", or "scaffold X" without explicitly mentioning React 19.4---5# React 19 Component Scaffolder
6
7Generate React 19/19.2 components, pages, hooks, and supporting files from parameterized templates. Every template enforces the patterns codified in the sibling `react` skill — refs as regular props (never `forwardRef`), Context rendered directly as provider (never `.Provider`), form actions with `useActionState` + `useFormStatus`, inline document metadata, `useSyncExternalStore` for external subscriptions, and YMNNAE-compliant hook bodies.
8
9## When to Apply
10
11- Creating a new React component (Server, Client, or unspecified — defaults to Server)
12- Adding a new route/page in a React 19 app
13- Building a form that needs progressive enhancement, optimistic UI, or pending state
14- Setting up a new Context provider with state + dispatch split
15- Writing a custom hook that subscribes to external state or wraps async work
16- Modeling complex state with a typed reducer
17- Adding document metadata (`<title>`, `<meta>`, `<link>`) or resource hints (`preload`, `preconnect`, `prefetchDNS`)
18- The user says "scaffold", "boilerplate", "generate", "new component", "new page", "new hook", or names any of the template types
19
20## Available Templates
21
22All filenames are kebab-case; the exported React identifier (`{Name}`, `use{Name}`) is PascalCase / camelCase.
23
24| # | Template | When to use | Files generated |
25|---|----------|-------------|-----------------|
26| 1 | [function-component](assets/templates/function-component.tsx.template) | Generic reusable component (works in Server or Client) | `{name-kebab}.tsx`, `{name-kebab}.test.tsx` |
27| 2 | [server-component-page](assets/templates/server-component-page.tsx.template) | Route page with server data fetch + Suspense + metadata | `page.tsx` |
28| 3 | [client-island](assets/templates/client-island.tsx.template) | `'use client'` interactivity nested inside a server page | `{name-kebab}-island.tsx`, `{name-kebab}-island.test.tsx` |
29| 4 | [form-action](assets/templates/form-action.tsx.template) | Mutation form with `useActionState` + Zod schema + server action | `{name-kebab}-form.tsx`, `actions.ts`, `schema.ts` |
30| 5 | [context-provider](assets/templates/context-provider.tsx.template) | Shared state with state/dispatch split and accessor hook | `{name-kebab}-context.tsx` |
31| 6 | [custom-hook](assets/templates/custom-hook.ts.template) | YMNNAE-compliant hook (external subscription or composed effect) | `use-{name-kebab}.ts`, `use-{name-kebab}.test.ts` |
32| 7 | [reducer](assets/templates/reducer.ts.template) | Typed reducer with discriminated-union actions + exhaustive switch | `{name-kebab}-reducer.ts`, `{name-kebab}-reducer.test.ts` |
33| 8 | [head-and-hints](assets/templates/head-and-hints.tsx.template) | Document metadata + resource hints for above-the-fold assets | `{name-kebab}-head.tsx` |
34
35## How to Use
36
371. **Identify the template** that matches the user's request. If ambiguous, ask. Default to `function-component` for unqualified "make me a component" requests.
382. **Read the template** at `assets/templates/{name}.template`.
393. **Read the related conventions** at `references/conventions.md` — every template emits code that obeys these conventions.
404. **Collect parameters** (see "Parameters" below). Ask the user only for parameters you cannot infer from context.
415. **Substitute placeholders** in the template. Every placeholder is wrapped in `{curly_braces}`. Empty placeholders (e.g., `{additional_hooks}` when there are none) collapse to empty string.
426. **Write each output file** using the Write tool. Use the path conventions in `config.json` (`module_path`, `route_path`).
437. **Mention the conventions enforced** so the user understands why the generated code looks the way it does (e.g., "I used `ref` as a prop rather than `forwardRef` because…").
44
45## Parameters
46
47Common parameters (most templates accept these):
48
49| Parameter | Required | Default | Description |
50|-----------|----------|---------|-------------|
51| `name` | yes | — | Component / hook / reducer identifier in PascalCase (or camelCase for hooks/reducers). The scaffolder derives `file_name` (kebab-case) and `name_kebab` automatically. |
52| `module_path` | no | `src/components` (or from `config.json`) | Directory under the project root for the generated files |
53| `props` | no | `[]` | List of `{name, type, required}` — emitted as the props interface |
54| `with_test` | no | `true` | Generate the matching `*.test.tsx` / `*.test.ts` file |
55| `with_ref` | no | `false` | Add `ref?: Ref<T>` to props (templates 1 and 3) |
56
57Template-specific parameters are documented in each template's leading comments.
58
59## Setup
60
61On first use, populate `config.json` with project-specific paths so generated files land in the right place. The defaults assume a standard `src/`-rooted project. To override interactively:
62
63- `module_path` — Where components live (e.g., `src/components`, `app/_components`)
64- `route_path` — Where Server Component pages live (e.g., `app/`, `src/routes/`)
65- `hooks_path` — Where custom hooks live (e.g., `src/hooks`)
66- `test_runner` — `vitest` (default) or `jest` (changes the imports in test templates)
67
68## Conforming Existing Code (Multi-File Refactor)
69
70When the user asks to **conform, modernize, or align existing components with this skill's conventions** across one or more files — not to generate new code — follow [`references/_conform-algorithm.md`](references/_conform-algorithm.md) instead of going file-by-file.
71
72Two non-negotiables from that doc:
73
741. **Judgment over grep.** Every convention is keyed off a syntactic marker (`forwardRef`, `<Context.Provider>`, `react-helmet`, `onSubmit=`, `react-dom/test-utils`). Grep finds the easy cases and *misses* the disguised ones — a manually drilled callback ref because the author dodged `forwardRef`, a bespoke `useState({ pending, error })` that's `useActionState` without the name, a `document.title` hand-roll. Use grep for inventory and post-hoc completeness only, never as the primary detector.
752. **Convention-major, not file-major.** Load all target files first, then sweep one convention at a time across all files in priority order (refs/context/forms first, naming/imports last). Reports group by convention, surfacing cross-file clusters.
76
77For brand-new scaffolds, skip this — go straight to a template.
78
79## React 19 Patterns This Skill Refuses to Generate
80
81- `forwardRef(...)` wrappers — emits `function Name({ ref, ...props })` instead
82- `<Context.Provider value={...}>` — emits `<Context value={...}>` instead
83- `useFormState` — emits `useActionState` instead
84- `onSubmit` handlers for mutations — emits `<form action={serverAction}>` instead
85- `useRef<T>()` without an argument — emits `useRef<T>(null)`
86- `useEffect` for derived state, parent notification, or POST-on-state-change — refuses entirely (see [conventions: State derivation](references/conventions.md))
87- `react-dom/test-utils` — emits `import { act } from '@testing-library/react'` instead
88- Manual `<link rel="preload">` JSX — emits `preload()` from `react-dom` instead
89- `react-helmet` / `react-helmet-async` — emits inline `<title>`/`<meta>`/`<link>` instead
90
91## Gotchas
92
93See [gotchas.md](gotchas.md). Empty on first release — gotchas accumulate as the skill is used.
94
95## Related Skills
96
97- [`react`](../react/SKILL.md) — Authoritative React 19 best-practices distillation (44 rules). The templates in this skill emit code that conforms to those rules.