Create React/Vue component with TypeScript, tests, and styles. Auto-invoke when user says "create component", "add component", "new component", or "build component".
Generate production-ready React/Vue components with TypeScript, tests, and styles following modern best practices.
Auto-invoke when user mentions:
Before gathering requirements, query the knowledge graph for what we already know about frontend/component work in this project. This mirrors navigator-research's Phase 0 and prevents re-deriving patterns we've already decided on.
PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$(cat "${NAVIGATOR_CONFIG_HOME:-${XDG_CONFIG_HOME:-$HOME/.config}/navigator}/plugin-root" 2>/dev/null)}"
[ -d "$PLUGIN_DIR/skills" ] || PLUGIN_DIR="$HOME/.claude/plugins/marketplaces/navigator-marketplace"
python3 "$PLUGIN_DIR/skills/nav-graph/functions/graph_manager.py" \
--action query --concept frontend \
--graph-path .agent/knowledge/graph.json 2>/dev/null | head -40
If memories surface (look for PATTERN, PITFALL, DECISION entries), read the full memory files for any directly relevant ones:
ls .agent/knowledge/memories/{patterns,pitfalls,decisions}/ 2>/dev/null
What to do with what you find:
pitfalls_avoided in Step 8)If the graph returns nothing useful, proceed without it. Skip this step only if the knowledge graph is disabled in .agent/.nav-config.json.
First, detect the framework: read package.json. If "next" is in dependencies, this is a Next.js App Router project ā use the Next.js variants in Step 3 and default styling to Tailwind (no CSS module file). See .agent/philosophy/NEXTJS-PATTERNS.md for the patterns these templates encode.
Ask user for component details:
Component name: [PascalCase name, e.g., UserProfile]
Component type:
Generic React:
- simple (basic functional component)
- with-hooks (useState, useEffect, etc.)
- container (data fetching component)
Next.js App Router:
- nextjs-page (app/<route>/page.tsx ā Server Component, async)
- nextjs-layout (app/<route>/layout.tsx ā Server Component, metadata + viewport)
- nextjs-server (Server Component with fetch, async)
- nextjs-client ('use client' component with state/effects)
Styling approach:
- tailwind (default for nextjs-* types)
- css-modules (default for generic React types)
- styled-components
Props needed: [Optional: describe expected props]
Picking the right Next.js variant:
nextjs-pagenextjs-layoutuseState" / "click handler" / "interactive" ā nextjs-clientnextjs-serverValidate component name:
functions/name_validator.pyIMPORTANT: This step MUST be executed for complex components.
Before generating files, confirm interpretation with user.
Display verification:
I understood you want:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Component: {NAME}
Type: {TYPE} (inferred because: {REASON})
Location: src/components/{NAME}/
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Detected patterns from your codebase:
- Styling: {CSS_APPROACH} (found {EVIDENCE})
- Testing: {TEST_LIBRARY} (found in package.json)
- Similar component: {EXISTING_COMPONENT} at {PATH}
Props I'll generate:
{PROPS_PREVIEW}
Proceed with generation? [Y/n]
Skip verification if (HIGH-STAKES ONLY mode):
Always verify if:
Based on component type and requirements:
Use predefined function: functions/props_interface_generator.py
# Generates TypeScript interface based on component requirements
python3 functions/props_interface_generator.py \
--name "UserProfile" \
--props "userId:string,onUpdate:function,isActive:boolean"
Output:
interface UserProfileProps {
userId: string;
onUpdate?: () => void;
isActive?: boolean;
children?: React.ReactNode;
className?: string;
}
Use appropriate template based on type:
Simple component:
Use template: templates/component-simple-template.tsx
Component with hooks / Container component:
Start from templates/component-simple-template.tsx and add the hook
declarations (useState/useEffect) or data-fetching logic inline ā there is
no separate with-hooks/container template file; the simple template is the base.
Next.js App Router variants (use when "next" is in package.json):
| --type | Template | Output path example |
|---|---|---|
nextjs-page |
templates/nextjs-page-template.tsx |
app/schedule/page.tsx |
nextjs-layout |
templates/nextjs-layout-template.tsx |
app/schedule/layout.tsx |
nextjs-server |
templates/nextjs-server-component-template.tsx |
app/components/speaker-list.tsx |
nextjs-client |
templates/nextjs-client-component-template.tsx |
app/components/favourite-button.tsx |
The Next.js templates already encode Next.js 15+/16 conventions:
params/searchParams are Promises ā await them'use client' directive on line 1 of client components, above all importsSkip Step 5 (Style File) for nextjs-* types ā Tailwind classes are baked into the templates, no CSS module needed.
Use predefined function: functions/component_generator.py
python3 functions/component_generator.py \
--name "UserProfile" \
--type "simple" \
--props-interface "UserProfileProps" \
--template "templates/component-simple-template.tsx" \
--output "src/components/UserProfile/UserProfile.tsx"
Template substitutions:
${COMPONENT_NAME} ā Component name (PascalCase)${PROPS_INTERFACE} ā Generated props interface${STYLE_IMPORT} ā CSS module import${DESCRIPTION} ā Brief component descriptionUse predefined function: functions/file_generator.py
python3 functions/file_generator.py \
--component-name "UserProfile" \
--component-path "src/components/UserProfile/UserProfile.tsx" \
--template "templates/test-template.tsx" \
--output "src/components/UserProfile/UserProfile.test.tsx"
Test template includes:
Template substitutions:
${COMPONENT_NAME} ā Component name${IMPORT_PATH} ā Relative import path${TEST_CASES} ā Generated test cases based on propsUse predefined function: functions/style_generator.py
python3 functions/style_generator.py \
--name "UserProfile" \
--approach "css-modules" \
--template "templates/style-template.module.css" \
--output "src/components/UserProfile/UserProfile.module.css"
CSS Modules template:
.container {
/* Component wrapper styles */
}
.title {
/* Title styles */
}
/* Add more classes as needed */
Styled Components alternative:
// Generated if --approach "styled-components"
import styled from 'styled-components';
export const Container = styled.div`
/* Component wrapper styles */
`;
export const Title = styled.h2`
/* Title styles */
`;
Create index.ts for clean imports:
Write(
file_path: "src/components/UserProfile/index.ts",
content: "export { UserProfile } from './UserProfile';\nexport type { UserProfileProps } from './UserProfile';\n"
)
Allows usage:
import { UserProfile } from '@/components/UserProfile';
Display generated files and usage:
ā
Component Created: UserProfile
Structure:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š src/components/UserProfile/
āāā UserProfile.tsx (Component)
āāā UserProfile.test.tsx (Tests)
āāā UserProfile.module.css (Styles)
āāā index.ts (Exports)
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Props Interface:
interface UserProfileProps {
userId: string;
onUpdate?: () => void;
isActive?: boolean;
}
Usage:
import { UserProfile } from '@/components/UserProfile';
<UserProfile
userId="123"
onUpdate={() => console.log('Updated')}
isActive={true}
/>
Next Steps:
1. Customize component implementation
2. Run tests: npm test UserProfile
3. Import and use in your feature
After Step 7, emit an execution_summary JSON block that captures patterns/decisions/pitfalls from this run. This block is the parity equivalent of the research_findings block emitted by navigator-research, and it gets ingested into the knowledge graph so future component work can surface what we learned.
Output the block verbatim (replace placeholders with actual values from this run):
{
"execution_summary": {
"skill": "frontend-component",
"task": "{COMPONENT_NAME} component",
"files_created": ["{paths of files written}"],
"files_modified": ["{paths of files edited}"],
"tests_added": ["{test file path}"],
"stack_detected": "{e.g. react+typescript+vitest}",
"patterns_followed": [
{"summary": "{convention applied ā e.g. functional component with Props interface}", "concepts": ["frontend"], "confidence": 0.8}
],
"decisions_made": [
{"summary": "{non-obvious choice ā e.g. React.memo because props are stable}", "concepts": ["frontend"], "confidence": 0.75, "evidence": "{path:line}"}
],
"pitfalls_avoided": [],
"assumptions_made": ["{e.g. project uses CSS Modules (detected via existing components)}"]
}
}
Ingestion (run from project root):
PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$(cat "${NAVIGATOR_CONFIG_HOME:-${XDG_CONFIG_HOME:-$HOME/.config}/navigator}/plugin-root" 2>/dev/null)}"
[ -d "$PLUGIN_DIR/skills" ] || PLUGIN_DIR="$HOME/.claude/plugins/marketplaces/navigator-marketplace"
echo '<execution_summary JSON>' | python3 "$PLUGIN_DIR/skills/nav-graph/functions/execution_to_graph.py" -
Rules:
decisions_made and pitfalls_avoided entries that are non-obvious and would help future runs.Validates component naming conventions.
Usage:
python3 functions/name_validator.py --name "UserProfile"
Checks:
Returns: Valid name or error message
Generates TypeScript props interface from user input.
Usage:
python3 functions/props_interface_generator.py \
--name "UserProfile" \
--props "userId:string,onUpdate:function,isActive:boolean"
Supported types:
string, number, booleanfunction (becomes () => void)array (becomes any[])object (becomes Record<string, any>)react-node (becomes React.ReactNode)Returns: TypeScript interface string
Generates component file from template with substitutions.
Usage:
python3 functions/component_generator.py \
--name "UserProfile" \
--type "simple" \
--props-interface "UserProfileProps" \
--template "templates/component-simple-template.tsx" \
--output "src/components/UserProfile/UserProfile.tsx"
Parameters:
--name: Component name (PascalCase)--type: Component type (simple/with-hooks/container)--props-interface: Props interface name--template: Template file path--output: Output file pathReturns: Generated component code
Generates test file with React Testing Library.
Usage:
python3 functions/file_generator.py \
--component-name "UserProfile" \
--component-path "src/components/UserProfile/UserProfile.tsx" \
--template "templates/test-template.tsx" \
--output "src/components/UserProfile/UserProfile.test.tsx"
Generates tests for:
Returns: Generated test code
Generates style file (CSS Modules or Styled Components).
Usage:
python3 functions/style_generator.py \
--name "UserProfile" \
--approach "css-modules" \
--template "templates/style-template.module.css" \
--output "src/components/UserProfile/UserProfile.module.css"
Supported approaches:
css-modules (default)styled-componentstailwind (generates className utilities)Returns: Generated style code
Basic functional component template.
Placeholders:
${COMPONENT_NAME} - Component name${PROPS_INTERFACE} - Props interface definition${STYLE_IMPORT} - CSS import statement${DESCRIPTION} - Component descriptionComponents needing hooks or data fetching start from
component-simple-template.tsx(above) and the model adds theuseState/useEffectdeclarations or fetch logic inline ā no dedicated with-hooks/container template ships.
React Testing Library test template.
Placeholders:
${COMPONENT_NAME} - Component name${IMPORT_PATH} - Import path${TEST_CASES} - Generated test casesCSS Modules template.
Placeholders:
${COMPONENT_NAME_KEBAB} - Component name in kebab-case${BASE_STYLES} - Base container stylesSee examples/ directory for reference implementations:
Each example includes:
any type (use unknown if needed)Problem: Generated component throws errors
Solutions:
Problem: Generated tests don't pass
Solutions:
--verbose flagProblem: CSS modules not loading
Solutions:
This skill succeeds when:
Auto-invoke this skill when creating React components to ensure consistency and save time āļø