Files
leo-claude-mktplace/plugins/saas-react-platform/skills/component-patterns.md
lmiranda 2d51df7a42 feat(marketplace): command consolidation + 8 new plugins (v8.1.0 → v9.0.0) [BREAKING]
Phase 1b: Rename all ~94 commands across 12 plugins to /<noun> <action>
sub-command pattern. Git-flow consolidated from 8→5 commands (commit
variants absorbed into --push/--merge/--sync flags). Dispatch files,
name: frontmatter, and cross-reference updates for all plugins.

Phase 2: Design documents for 8 new plugins in docs/designs/.

Phase 3: Scaffold 8 new plugins — saas-api-platform, saas-db-migrate,
saas-react-platform, saas-test-pilot, data-seed, ops-release-manager,
ops-deploy-pipeline, debug-mcp. Each with plugin.json, commands, agents,
skills, README, and claude-md-integration. Marketplace grows from 12→20.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 14:52:11 -05:00

3.9 KiB

name, description
name description
component-patterns Component structure conventions including functional components, prop typing, exports, and co-located tests

Component Patterns

Purpose

Define standard patterns for React component scaffolding. This skill ensures all generated components follow consistent structure, typing, export conventions, and test co-location.


Component File Structure

Every component file follows this order:

// 1. Imports (external first, then internal, then styles)
import { type FC } from 'react';
import { Button } from '@/components/ui/Button';
import styles from './ComponentName.module.css';

// 2. Types (inline for simple, separate file for complex)
interface ComponentNameProps {
  title: string;
  onAction: () => void;
  children?: React.ReactNode;
}

// 3. Component definition
/**
 * Brief description of what this component does.
 *
 * @component
 * @example
 * <ComponentName title="Hello" onAction={() => console.log('clicked')} />
 */
const ComponentName: FC<ComponentNameProps> = ({ title, onAction, children }) => {
  return (
    <div>
      <h2>{title}</h2>
      {children}
      <button onClick={onAction}>Action</button>
    </div>
  );
};

// 4. Display name (for DevTools)
ComponentName.displayName = 'ComponentName';

// 5. Export
export default ComponentName;

Component Type Templates

UI Component (presentational)

  • Props in, JSX out — no side effects, no data fetching
  • Pure function: same props always produce same output
  • Accept className prop for style override flexibility
  • Accept children if component is a container/wrapper

Page Component

  • Includes data fetching (server component in App Router, useEffect in client)
  • Loading state with skeleton placeholder
  • Error state with retry action
  • 'use client' directive only if client interactivity required (App Router)

Layout Component

  • Accepts children: React.ReactNode as required prop
  • Optional slot props for sidebar, header, footer
  • Handles responsive behavior
  • Wraps with error boundary

Form Component

  • Controlled inputs with useState or form library (react-hook-form)
  • Typed form values interface
  • Validation schema (Zod recommended)
  • Submit handler with loading state
  • Error display per field and form-level

Test Co-location Patterns

Test file sits next to component file:

src/components/Button/
  Button.tsx
  Button.test.tsx
  Button.module.css  (if CSS Modules)
  index.ts           (barrel file)

Minimum Test Coverage

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ComponentName from './ComponentName';

describe('ComponentName', () => {
  it('renders without crashing', () => {
    render(<ComponentName title="Test" onAction={() => {}} />);
    expect(screen.getByText('Test')).toBeInTheDocument();
  });

  it('calls onAction when button clicked', async () => {
    const onAction = vi.fn();
    render(<ComponentName title="Test" onAction={onAction} />);
    await userEvent.click(screen.getByRole('button'));
    expect(onAction).toHaveBeenCalledOnce();
  });
});

Barrel File Convention

Each component directory exports through index.ts:

export { default as ComponentName } from './ComponentName';
export type { ComponentNameProps } from './ComponentName';

Anti-Patterns to Avoid

Pattern Why Alternative
Class components Legacy API, verbose Functional components + hooks
React.FC with children Children always optional, incorrect type narrowing Explicit children prop in interface
Prop spreading {...props} Obscures expected interface Explicitly destructure needed props
useEffect for derived state Unnecessary render cycle Compute during render or useMemo
forwardRef without displayName Unnamed in DevTools Always set displayName