name: react-19-component-scaffolder
description: 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, , 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.
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-componentfor 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
refas a prop rather thanforwardRefbecause…").
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) orjest(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 dodgedforwardRef, a bespokeuseState({ pending, error })that'suseActionStatewithout the name, adocument.titlehand-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 — emitsfunction Name({ ref, ...props })instead<Context.Provider value={...}>— emits<Context value={...}>insteaduseFormState— emitsuseActionStateinsteadonSubmithandlers for mutations — emits<form action={serverAction}>insteaduseRef<T>()without an argument — emitsuseRef<T>(null)useEffectfor derived state, parent notification, or POST-on-state-change — refuses entirely (see conventions: State derivation)react-dom/test-utils— emitsimport { act } from '@testing-library/react'instead- Manual
<link rel="preload">JSX — emitspreload()fromreact-dominstead 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.