Overview
Creates complete, production-grade React functional components using TypeScript. The skill outputs a component with a strict Props interface (using interface or type), sensible default props via destructuring, full JSDoc, proper forwardRef when needed, React.memo guidance, data-testid attributes for testing, a basic Storybook story stub, and accessibility considerations baked in.
When to Use This Skill
- Scaffolding a new UI component in a React + TypeScript project.
- The user provides a component name, list of props, behavior description, or a design spec/wireframe.
- You need consistent, high-quality component boilerplate that follows team conventions (props naming, JSDoc, testing attributes).
- Starting a component library, design system, or feature with many similar components.
Prerequisites
- Existing React project (Next.js, Vite, CRA, or custom) using TypeScript.
- Component library conventions already established (or the skill will propose sensible defaults).
react and @types/react installed (version 18+ recommended).
- For Storybook stories: Storybook 7+ or 8+ configured in the project.
- Optional but recommended:
clsx or tailwind-merge for className merging if using Tailwind.
Steps
Gather component specification:
- Component name (PascalCase).
- List of props with types and whether they are required.
- Behavioral description (what it does, variants, states).
- Accessibility requirements.
- Whether it needs
ref forwarding, children, or complex state.
- Styling approach (Tailwind, CSS Modules, styled-components, plain CSS).
Define the Props interface:
- Use
interface ComponentNameProps { ... } (preferred for declaration merging).
- Make optional props explicit with
?.
- Use union types for variants (e.g.,
variant?: 'primary' | 'secondary' | 'danger').
- Include
className?: string and children?: React.ReactNode where appropriate.
- Add JSDoc to every prop.
Implement the component function:
- Use arrow function with explicit return type
React.FC<ComponentNameProps> or just the function for better tree-shaking.
- Destructure props with defaults:
const { variant = 'primary', ... } = props;.
- Apply
React.forwardRef when the component renders a DOM element that should expose a ref (buttons, inputs, etc.).
- Use
React.memo only when the component is pure and props are frequently stable (document the decision).
Add accessibility and ARIA:
- Include
aria-* attributes based on role and state.
- Use semantic HTML elements inside the component.
- Add
role only when necessary (avoid over-using).
Include testing helpers:
- Add
data-testid={testId || 'component-name'} on the root or key interactive elements.
- Suggest a basic test file structure using React Testing Library.
Generate a Storybook story stub:
- Create a
.stories.tsx file with the component imported.
- Include controls for all variants and states.
- Add a "Playground" story and 2-3 specific stories (e.g., "Primary", "Disabled", "WithIcon").
Handle styling:
- If Tailwind: use
clsx or template literals with conditional classes.
- Provide a
cn utility example if the project doesn't have one.
- Keep style logic inside the component or extract to a separate
variants.ts when complex.
Add JSDoc and displayName:
- Top-level JSDoc describing the component purpose and usage.
Component.displayName = 'ComponentName'; for better debugging in React DevTools.
Output files:
- The main component file (
ComponentName.tsx).
- The story file (
ComponentName.stories.tsx).
- Optional: a basic test file skeleton.
- Usage example in the skill response.
Recommend follow-up:
- If form-related, suggest
form-validator.
- If animation needed, suggest
css-animation-crafter.
Examples
Example 1: Button Component
User request: "Create a Button component in React + TS. Variants: primary, secondary, ghost, danger. Sizes: sm, md, lg. Supports disabled, loading, left/right icon, and full width. Use Tailwind."
Generated Component (abbreviated for brevity in this example; full in real output):
import React from 'react';
import { clsx } from 'clsx';
export interface ButtonProps {
/** Visual style variant */
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
/** Size variant */
size?: 'sm' | 'md' | 'lg';
/** Whether the button is in a loading state */
isLoading?: boolean;
/** Left icon element */
leftIcon?: React.ReactNode;
/** Right icon element */
rightIcon?: React.ReactNode;
/** Make button take full width of container */
fullWidth?: boolean;
/** Disable the button */
disabled?: boolean;
children: React.ReactNode;
className?: string;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
/**
* A versatile, accessible button component with multiple variants and states.
*
* @example
* <Button variant="primary" size="md">Click me</Button>
*/
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
variant = 'primary',
size = 'md',
isLoading = false,
leftIcon,
rightIcon,
fullWidth = false,
disabled,
children,
className,
...props
},
ref
) => {
const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none';
const variantStyles = {
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-500',
ghost: 'text-gray-700 hover:bg-gray-100 focus:ring-gray-500',
danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
};
const sizeStyles = {
sm: 'px-3 py-1.5 text-sm gap-1.5',
md: 'px-4 py-2 text-base gap-2',
lg: 'px-6 py-3 text-lg gap-2.5',
};
return (
<button
ref={ref}
type="button"
disabled={disabled || isLoading}
className={clsx(
baseStyles,
variantStyles[variant],
sizeStyles[size],
fullWidth && 'w-full',
className
)}
aria-busy={isLoading}
data-testid="button"
{...props}
>
{isLoading && <span className="animate-spin mr-2">⏳</span>}
{leftIcon && <span className="mr-2">{leftIcon}</span>}
{children}
{rightIcon && <span className="ml-2">{rightIcon}</span>}
</button>
);
}
);
Button.displayName = 'Button';
Storybook stub also generated with all controls.
Example 2: Card with children and ref forwarding (similar detailed output).
Edge Cases & Error Handling
- Polymorphic component (as="a" or as="div"): Provide an
as prop using a generic or asChild pattern with Radix-style slot if the project uses it. Otherwise, keep it simple with a Component variable.
- Complex children: Document when to use
children vs dedicated props (e.g., title and description for a card).
- Performance: If the component renders lists or has expensive children, document when to wrap with
React.memo and provide a custom areEqual example.
- TypeScript strictness: Always use
strict mode friendly types. Avoid any. Use React.ComponentPropsWithoutRef<'button'> for native props spreading when appropriate.
- Icon libraries: Show how to accept
React.ReactNode for icons so any icon library works (Heroicons, Lucide, etc.).
- Ref forwarding with generics: Provide the correct generic signature for
forwardRef.
Verification
- Create the files in the project.
- Run
npm run build or tsc --noEmit — zero TypeScript errors.
- Import and render the component in a page or Storybook. Verify it matches the spec.
- Open React DevTools — confirm
displayName is set and props look clean.
- Run Storybook and interact with all controls.
- Write a quick test using the
data-testid and run it with your test runner.
- Check accessibility with axe or Lighthouse on a story that exercises all states.
- Success: Component is typed correctly, renders without warnings, passes tests, and is easy for other developers to use and extend.
References
Source: Nikoxkx/Agent-Skills — distributed by TomeVault.
1---2name: react-component-generator3description: Generates production-ready React functional components with TypeScript, props interface, default props, and JSDoc. Use when scaffolding new React components from descriptions or design specs.4license: Apache-2.05---67## Overview89Creates complete, production-grade React functional components using TypeScript. The skill outputs a component with a strict `Props` interface (using `interface` or `type`), sensible default props via destructuring, full JSDoc, proper `forwardRef` when needed, `React.memo` guidance, `data-testid` attributes for testing, a basic Storybook story stub, and accessibility considerations baked in.1011## When to Use This Skill1213- Scaffolding a new UI component in a React + TypeScript project.14- The user provides a component name, list of props, behavior description, or a design spec/wireframe.15- You need consistent, high-quality component boilerplate that follows team conventions (props naming, JSDoc, testing attributes).16- Starting a component library, design system, or feature with many similar components.1718## Prerequisites1920- Existing React project (Next.js, Vite, CRA, or custom) using TypeScript.21- Component library conventions already established (or the skill will propose sensible defaults).22- `react` and `@types/react` installed (version 18+ recommended).23- For Storybook stories: Storybook 7+ or 8+ configured in the project.24- Optional but recommended: `clsx` or `tailwind-merge` for className merging if using Tailwind.2526## Steps27281. **Gather component specification**:29 - Component name (PascalCase).30 - List of props with types and whether they are required.31 - Behavioral description (what it does, variants, states).32 - Accessibility requirements.33 - Whether it needs `ref` forwarding, children, or complex state.34 - Styling approach (Tailwind, CSS Modules, styled-components, plain CSS).35362. **Define the Props interface**:37 - Use `interface ComponentNameProps { ... }` (preferred for declaration merging).38 - Make optional props explicit with `?`.39 - Use union types for variants (e.g., `variant?: 'primary' | 'secondary' | 'danger'`).40 - Include `className?: string` and `children?: React.ReactNode` where appropriate.41 - Add JSDoc to every prop.42433. **Implement the component function**:44 - Use arrow function with explicit return type `React.FC<ComponentNameProps>` or just the function for better tree-shaking.45 - Destructure props with defaults: `const { variant = 'primary', ... } = props;`.46 - Apply `React.forwardRef` when the component renders a DOM element that should expose a ref (buttons, inputs, etc.).47 - Use `React.memo` only when the component is pure and props are frequently stable (document the decision).48494. **Add accessibility and ARIA**:50 - Include `aria-*` attributes based on role and state.51 - Use semantic HTML elements inside the component.52 - Add `role` only when necessary (avoid over-using).53545. **Include testing helpers**:55 - Add `data-testid={testId || 'component-name'}` on the root or key interactive elements.56 - Suggest a basic test file structure using React Testing Library.57586. **Generate a Storybook story stub**:59 - Create a `.stories.tsx` file with the component imported.60 - Include controls for all variants and states.61 - Add a "Playground" story and 2-3 specific stories (e.g., "Primary", "Disabled", "WithIcon").62637. **Handle styling**:64 - If Tailwind: use `clsx` or template literals with conditional classes.65 - Provide a `cn` utility example if the project doesn't have one.66 - Keep style logic inside the component or extract to a separate `variants.ts` when complex.67688. **Add JSDoc and displayName**:69 - Top-level JSDoc describing the component purpose and usage.70 - `Component.displayName = 'ComponentName';` for better debugging in React DevTools.71729. **Output files**:73 - The main component file (`ComponentName.tsx`).74 - The story file (`ComponentName.stories.tsx`).75 - Optional: a basic test file skeleton.76 - Usage example in the skill response.777810. **Recommend follow-up**:79 - If form-related, suggest `form-validator`.80 - If animation needed, suggest `css-animation-crafter`.8182## Examples8384**Example 1: Button Component**8586**User request**: "Create a Button component in React + TS. Variants: primary, secondary, ghost, danger. Sizes: sm, md, lg. Supports disabled, loading, left/right icon, and full width. Use Tailwind."8788**Generated Component** (abbreviated for brevity in this example; full in real output):8990```tsx91import React from 'react';92import { clsx } from 'clsx';9394export interface ButtonProps {95 /** Visual style variant */96 variant?: 'primary' | 'secondary' | 'ghost' | 'danger';97 /** Size variant */98 size?: 'sm' | 'md' | 'lg';99 /** Whether the button is in a loading state */100 isLoading?: boolean;101 /** Left icon element */102 leftIcon?: React.ReactNode;103 /** Right icon element */104 rightIcon?: React.ReactNode;105 /** Make button take full width of container */106 fullWidth?: boolean;107 /** Disable the button */108 disabled?: boolean;109 children: React.ReactNode;110 className?: string;111 onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;112}113114/**115 * A versatile, accessible button component with multiple variants and states.116 * 117 * @example118 * <Button variant="primary" size="md">Click me</Button>119 */120export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(121 (122 {123 variant = 'primary',124 size = 'md',125 isLoading = false,126 leftIcon,127 rightIcon,128 fullWidth = false,129 disabled,130 children,131 className,132 ...props133 },134 ref135 ) => {136 const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none';137 138 const variantStyles = {139 primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',140 secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-500',141 ghost: 'text-gray-700 hover:bg-gray-100 focus:ring-gray-500',142 danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',143 };144145 const sizeStyles = {146 sm: 'px-3 py-1.5 text-sm gap-1.5',147 md: 'px-4 py-2 text-base gap-2',148 lg: 'px-6 py-3 text-lg gap-2.5',149 };150151 return (152 <button153 ref={ref}154 type="button"155 disabled={disabled || isLoading}156 className={clsx(157 baseStyles,158 variantStyles[variant],159 sizeStyles[size],160 fullWidth && 'w-full',161 className162 )}163 aria-busy={isLoading}164 data-testid="button"165 {...props}166 >167 {isLoading && <span className="animate-spin mr-2">⏳</span>}168 {leftIcon && <span className="mr-2">{leftIcon}</span>}169 {children}170 {rightIcon && <span className="ml-2">{rightIcon}</span>}171 </button>172 );173 }174);175176Button.displayName = 'Button';177```178179**Storybook stub** also generated with all controls.180181**Example 2: Card with children and ref forwarding** (similar detailed output).182183## Edge Cases & Error Handling184185- **Polymorphic component** (as="a" or as="div"): Provide an `as` prop using a generic or `asChild` pattern with Radix-style slot if the project uses it. Otherwise, keep it simple with a `Component` variable.186- **Complex children**: Document when to use `children` vs dedicated props (e.g., `title` and `description` for a card).187- **Performance**: If the component renders lists or has expensive children, document when to wrap with `React.memo` and provide a custom `areEqual` example.188- **TypeScript strictness**: Always use `strict` mode friendly types. Avoid `any`. Use `React.ComponentPropsWithoutRef<'button'>` for native props spreading when appropriate.189- **Icon libraries**: Show how to accept `React.ReactNode` for icons so any icon library works (Heroicons, Lucide, etc.).190- **Ref forwarding with generics**: Provide the correct generic signature for `forwardRef`.191192## Verification1931941. Create the files in the project.1952. Run `npm run build` or `tsc --noEmit` — zero TypeScript errors.1963. Import and render the component in a page or Storybook. Verify it matches the spec.1974. Open React DevTools — confirm `displayName` is set and props look clean.1985. Run Storybook and interact with all controls.1996. Write a quick test using the `data-testid` and run it with your test runner.2007. Check accessibility with axe or Lighthouse on a story that exercises all states.2018. Success: Component is typed correctly, renders without warnings, passes tests, and is easy for other developers to use and extend.202203## References204205- [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/)206- [Storybook for React](https://storybook.js.org/docs/react/get-started/introduction)207- [React.forwardRef Documentation](https://react.dev/reference/react/forwardRef)208- [React.memo](https://react.dev/reference/react/memo)209- Project's existing component library for style alignment (ask user for link or examples)210211---212> Source: [Nikoxkx/Agent-Skills](https://github.com/Nikoxkx/Agent-Skills) — distributed by [TomeVault](https://tomevault.io).213<!-- tomevault:4.0:skill_md:2026-06-15 -->