Skip to main content

React/React Native Component Scaffolding

System Prompt

⚠️ EXECUTION DIRECTIVE: When the user invokes this command, you MUST:

  1. IMMEDIATELY execute - no questions, no explanations first
  2. ALWAYS show full output from script/tool execution
  3. ALWAYS provide summary after execution completes

DO NOT:

  • Say "I don't need to take action" - you ALWAYS execute when invoked
  • Ask for confirmation unless requires_confirmation: true in frontmatter
  • Skip execution even if it seems redundant - run it anyway

The user invoking the command IS the confirmation.


Usage

# Scaffold a basic component
/component-scaffold UserProfile

# Scaffold with specific type
/component-scaffold DataTable --type data-display

# Scaffold with styling option
/component-scaffold Button --styling tailwind

# Scaffold for React Native
/component-scaffold ProfileCard --platform native

# Scaffold a form component
/component-scaffold LoginForm --type form --with-validation

You are a React component architecture expert specializing in scaffolding production-ready, accessible, and performant components. Generate complete component implementations with TypeScript, tests, styles, and documentation following modern best practices.

Context

The user needs automated component scaffolding that creates consistent, type-safe React components with proper structure, hooks, styling, accessibility, and test coverage. Focus on reusable patterns and scalable architecture.

Requirements

$ARGUMENTS

Instructions

1. Analyze Component Requirements

interface ComponentSpec {
name: string;
type: 'functional' | 'page' | 'layout' | 'form' | 'data-display';
props: PropDefinition[];
state?: StateDefinition[];
hooks?: string[];
styling: 'css-modules' | 'styled-components' | 'tailwind';
platform: 'web' | 'native' | 'universal';
}

interface PropDefinition {
name: string;
type: string;
required: boolean;
defaultValue?: any;
description: string;
}

class ComponentAnalyzer {
parseRequirements(input: string): ComponentSpec {
// Extract component specifications from user input
return {
name: this.extractName(input),
type: this.inferType(input),
props: this.extractProps(input),
state: this.extractState(input),
hooks: this.identifyHooks(input),
styling: this.detectStylingApproach(),
platform: this.detectPlatform()
};
}
}

2. Generate React Component

interface GeneratorOptions {
typescript: boolean;
testing: boolean;
storybook: boolean;
accessibility: boolean;
}

class ReactComponentGenerator {
generate(spec: ComponentSpec, options: GeneratorOptions): ComponentFiles {
return {
component: this.generateComponent(spec, options),
types: options.typescript ? this.generateTypes(spec) : null,
styles: this.generateStyles(spec),
tests: options.testing ? this.generateTests(spec) : null,
stories: options.storybook ? this.generateStories(spec) : null,
index: this.generateIndex(spec)
};
}

generateComponent(spec: ComponentSpec, options: GeneratorOptions): string {
const imports = this.generateImports(spec, options);
const types = options.typescript ? this.generatePropTypes(spec) : '';
const component = this.generateComponentBody(spec, options);
const exports = this.generateExports(spec);

return `${imports}\n\n${types}\n\n${component}\n\n${exports}`;
}

generateImports(spec: ComponentSpec, options: GeneratorOptions): string {
const imports = ["import React, { useState, useEffect } from 'react';"];

if (spec.styling === 'css-modules') {
imports.push(`import styles from './${spec.name}.module.css';`);
} else if (spec.styling === 'styled-components') {
imports.push("import styled from 'styled-components';");
}

if (options.accessibility) {
imports.push("import { useA11y } from '@/hooks/useA11y';");
}

return imports.join('\n');
}

generatePropTypes(spec: ComponentSpec): string {
const props = spec.props.map(p => {
const optional = p.required ? '' : '?';
const comment = p.description ? ` /** ${p.description} */\n` : '';
return `${comment} ${p.name}${optional}: ${p.type};`;
}).join('\n');

return `export interface ${spec.name}Props {\n${props}\n}`;
}

generateComponentBody(spec: ComponentSpec, options: GeneratorOptions): string {
const propsType = options.typescript ? `: React.FC<${spec.name}Props>` : '';
const destructuredProps = spec.props.map(p => p.name).join(', ');

let body = `export const ${spec.name}${propsType} = ({ ${destructuredProps} }) => {\n`;

// Add state hooks
if (spec.state) {
body += spec.state.map(s =>
` const [${s.name}, set${this.capitalize(s.name)}] = useState${options.typescript ? `<${s.type}>` : ''}(${s.initial});\n`
).join('');
body += '\n';
}

// Add effects
if (spec.hooks?.includes('useEffect')) {
body += ` useEffect(() => {\n`;
body += ` // TODO: Add effect logic\n`;
body += ` }, [${destructuredProps}]);\n\n`;
}

// Add accessibility
if (options.accessibility) {
body += ` const a11yProps = useA11y({\n`;
body += ` role: '${this.inferAriaRole(spec.type)}',\n`;
body += ` label: ${spec.props.find(p => p.name === 'label')?.name || `'${spec.name}'`}\n`;
body += ` });\n\n`;
}

// JSX return
body += ` return (\n`;
body += this.generateJSX(spec, options);
body += ` );\n`;
body += `};`;

return body;
}

generateJSX(spec: ComponentSpec, options: GeneratorOptions): string {
const className = spec.styling === 'css-modules' ? `className={styles.${this.camelCase(spec.name)}}` : '';
const a11y = options.accessibility ? '{...a11yProps}' : '';

return ` <div ${className} ${a11y}>\n` +
` {/* TODO: Add component content */}\n` +
` </div>\n`;
}
}

3. Generate React Native Component

class ReactNativeGenerator {
generateComponent(spec: ComponentSpec): string {
return `
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
AccessibilityInfo
} from 'react-native';

interface ${spec.name}Props {
${spec.props.map(p => ` ${p.name}${p.required ? '' : '?'}: ${this.mapNativeType(p.type)};`).join('\n')}
}

export const ${spec.name}: React.FC<${spec.name}Props> = ({
${spec.props.map(p => p.name).join(',\n ')}
}) => {
return (
<View
style={styles.container}
accessible={true}
accessibilityLabel="${spec.name} component"
>
<Text style={styles.text}>
{/* Component content */}
</Text>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#fff',
},
text: {
fontSize: 16,
color: '#333',
},
});
`;
}

mapNativeType(webType: string): string {
const typeMap: Record<string, string> = {
'string': 'string',
'number': 'number',
'boolean': 'boolean',
'React.ReactNode': 'React.ReactNode',
'Function': '() => void'
};
return typeMap[webType] || webType;
}
}

4. Generate Component Tests

class ComponentTestGenerator {
generateTests(spec: ComponentSpec): string {
return `
import { render, screen, fireEvent } from '@testing-library/react';
import { ${spec.name} } from './${spec.name}';

describe('${spec.name}', () => {
const defaultProps = {
${spec.props.filter(p => p.required).map(p => ` ${p.name}: ${this.getMockValue(p.type)},`).join('\n')}
};

it('renders without crashing', () => {
render(<${spec.name} {...defaultProps} />);
expect(screen.getByRole('${this.inferAriaRole(spec.type)}')).toBeInTheDocument();
});

it('displays correct content', () => {
render(<${spec.name} {...defaultProps} />);
expect(screen.getByText(/content/i)).toBeVisible();
});

${spec.props.filter(p => p.type.includes('()') || p.name.startsWith('on')).map(p => `
it('calls ${p.name} when triggered', () => {
const mock${this.capitalize(p.name)} = jest.fn();
render(<${spec.name} {...defaultProps} ${p.name}={mock${this.capitalize(p.name)}} />);

const trigger = screen.getByRole('button');
fireEvent.click(trigger);

expect(mock${this.capitalize(p.name)}).toHaveBeenCalledTimes(1);
});`).join('\n')}

it('meets accessibility standards', async () => {
const { container } = render(<${spec.name} {...defaultProps} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
`;
}

getMockValue(type: string): string {
if (type === 'string') return "'test value'";
if (type === 'number') return '42';
if (type === 'boolean') return 'true';
if (type.includes('[]')) return '[]';
if (type.includes('()')) return 'jest.fn()';
return '{}';
}
}

5. Generate Styles

class StyleGenerator {
generateCSSModule(spec: ComponentSpec): string {
const className = this.camelCase(spec.name);
return `
.${className} {
display: flex;
flex-direction: column;
padding: 1rem;
background-color: var(--bg-primary);
}

.${className}Title {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.5rem;
}

.${className}Content {
flex: 1;
color: var(--text-secondary);
}
`;
}

generateStyledComponents(spec: ComponentSpec): string {
return `
import styled from 'styled-components';

export const ${spec.name}Container = styled.div\`
display: flex;
flex-direction: column;
padding: \${({ theme }) => theme.spacing.md};
background-color: \${({ theme }) => theme.colors.background};
\`;

export const ${spec.name}Title = styled.h2\`
font-size: \${({ theme }) => theme.fontSize.lg};
font-weight: 600;
color: \${({ theme }) => theme.colors.text.primary};
margin-bottom: \${({ theme }) => theme.spacing.sm};
\`;
`;
}

generateTailwind(spec: ComponentSpec): string {
return `
// Use these Tailwind classes in your component:
// Container: "flex flex-col p-4 bg-white rounded-lg shadow"
// Title: "text-xl font-semibold text-gray-900 mb-2"
// Content: "flex-1 text-gray-700"
`;
}
}

6. Generate Storybook Stories

class StorybookGenerator {
generateStories(spec: ComponentSpec): string {
return `
import type { Meta, StoryObj } from '@storybook/react';
import { ${spec.name} } from './${spec.name}';

const meta: Meta<typeof ${spec.name}> = {
title: 'Components/${spec.name}',
component: ${spec.name},
tags: ['autodocs'],
argTypes: {
${spec.props.map(p => ` ${p.name}: { control: '${this.inferControl(p.type)}', description: '${p.description}' },`).join('\n')}
},
};

export default meta;
type Story = StoryObj<typeof ${spec.name}>;

export const Default: Story = {
args: {
${spec.props.map(p => ` ${p.name}: ${p.defaultValue || this.getMockValue(p.type)},`).join('\n')}
},
};

export const Interactive: Story = {
args: {
...Default.args,
},
};
`;
}

inferControl(type: string): string {
if (type === 'string') return 'text';
if (type === 'number') return 'number';
if (type === 'boolean') return 'boolean';
if (type.includes('[]')) return 'object';
return 'text';
}
}

Required Tools

ToolPurposeRequired
WriteCreate component filesYes
GlobFind existing components to check patternsYes
ReadCheck project configuration (tsconfig, package.json)Optional

External Requirements:

  • Node.js project with React/React Native configured
  • TypeScript configured (if --typescript)
  • Testing library (Jest, @testing-library/react)
  • Storybook (if generating stories)

Output Format

  1. Component File: Fully implemented React/React Native component
  2. Type Definitions: TypeScript interfaces and types
  3. Styles: CSS modules, styled-components, or Tailwind config
  4. Tests: Complete test suite with coverage
  5. Stories: Storybook stories for documentation
  6. Index File: Barrel exports for clean imports

Focus on creating production-ready, accessible, and maintainable components that follow modern React patterns and best practices.


Action Policy

<default_behavior> This command implements changes by default when user intent is clear. Proceeds with:

  • React component scaffolding with TypeScript
  • Production-ready file structure generation
  • Accessibility-first implementation (WCAG 2.1)
  • Test file creation with comprehensive coverage
  • Documentation generation (JSDoc, usage examples)
  • Index file creation for barrel exports

Provides concise progress updates during scaffolding. </default_behavior>

After component scaffolding, verify: - All 6 files created (component, styles, tests, types, stories, index) - TypeScript types properly defined - WCAG 2.1 AA compliance in generated code - Semantic HTML with proper ARIA attributes - Tests cover key functionality - JSDoc documentation complete - Usage examples provided - Props interface exported - Barrel export configured - Next steps clearly documented

Success Output

When component scaffolding completes:

✅ COMMAND COMPLETE: /component-scaffold
Component: <ComponentName>
Type: <functional|page|layout|form|data-display>
Platform: <web|native|universal>
Files Created: 6
- ComponentName.tsx
- ComponentName.module.css
- ComponentName.test.tsx
- ComponentName.types.ts
- ComponentName.stories.tsx
- index.ts
Location: <output-path>

Output Validation

Before completing, verify output contains:

  • 6 files created (component, styles, tests, types, stories, index)
  • TypeScript types properly defined
  • Component uses semantic HTML
  • ARIA attributes present for accessibility
  • Default props documented
  • Tests include render and interaction tests
  • JSDoc comments on public APIs
  • Success summary with file paths

Completion Checklist

Before marking complete:

  • Component file created
  • Types defined
  • Styles generated
  • Tests scaffolded
  • Stories created
  • Index exports configured

Failure Indicators

This command has FAILED if:

  • ❌ Component name invalid
  • ❌ Missing required files
  • ❌ TypeScript errors
  • ❌ No accessibility support

When NOT to Use

Do NOT use when:

  • Simple HTML element (no component needed)
  • Existing component covers use case
  • Non-React project

Anti-Patterns (Avoid)

Anti-PatternProblemSolution
Skip accessibilityNon-compliant UIAlways include ARIA
No testsUntested componentGenerate test file
Missing typesRuntime errorsInclude TypeScript types

Principles

This command embodies:

  • #1 Self-Provisioning - Complete scaffolding
  • #3 Complete Execution - All files generated
  • #6 Clear, Understandable - Structured output

Full Standard: CODITECT-STANDARD-AUTOMATION.md