skills/smithery.ai/frontend-react-components

frontend-react-components

SKILL.md

Frontend React Components

When to use this skill

  • Creating new React components
  • Refactoring existing components
  • Establishing component standards in a project
  • Code reviews for component quality

Workflow

  • Identify component responsibility (single purpose)
  • Choose component type (presentation vs container)
  • Define prop interface with TypeScript
  • Implement component with proper patterns
  • Add prop validation and defaults
  • Test component in isolation

Instructions

Component Structure

Basic Functional Component

import { FC } from 'react';

interface ButtonProps {
  children: React.ReactNode;
  variant?: 'primary' | 'secondary';
  onClick?: () => void;
  disabled?: boolean;
}

export const Button: FC<ButtonProps> = ({
  children,
  variant = 'primary',
  onClick,
  disabled = false
}) => {
  return (
    <button
      className={`btn btn-${variant}`}
      onClick={onClick}
      disabled={disabled}
    >
      {children}
    </button>
  );
};

Component Patterns

1. Compound Components

export const Card = ({ children }: { children: React.ReactNode }) => {
  return <div className="card">{children}</div>;
};

Card.Header = ({ children }: { children: React.ReactNode }) => {
  return <div className="card-header">{children}</div>;
};

Card.Body = ({ children }: { children: React.ReactNode }) => {
  return <div className="card-body">{children}</div>;
};

// Usage
<Card>
  <Card.Header>Title</Card.Header>
  <Card.Body>Content</Card.Body>
</Card>

2. Render Props

interface DataFetcherProps<T> {
  url: string;
  children: (data: T | null, loading: boolean) => React.ReactNode;
}

export function DataFetcher<T>({ url, children }: DataFetcherProps<T>) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, [url]);

  return <>{children(data, loading)}</>;
}

// Usage
<DataFetcher<User> url="/api/user">
  {(user, loading) => (
    loading ? <Spinner /> : <UserProfile user={user} />
  )}
</DataFetcher>

3. Controlled vs Uncontrolled

// Controlled
export function ControlledInput({ value, onChange }: {
  value: string;
  onChange: (value: string) => void;
}) {
  return (
    <input
      value={value}
      onChange={e => onChange(e.target.value)}
    />
  );
}

// Uncontrolled
export function UncontrolledInput({ defaultValue }: {
  defaultValue?: string;
}) {
  const inputRef = useRef<HTMLInputElement>(null);
  
  return <input ref={inputRef} defaultValue={defaultValue} />;
}

Prop Design

Do's:

  • Use TypeScript interfaces
  • Provide sensible defaults
  • Keep props simple and focused
  • Use discriminated unions for variants
type ButtonProps = 
  | { variant: 'primary'; onClick: () => void }
  | { variant: 'link'; href: string };

Don'ts:

  • Avoid boolean props for variants (use enums)
  • Don't pass entire objects when you need one property
  • Avoid deeply nested prop structures

File Organization

components/
├── Button/
│   ├── Button.tsx
│   ├── Button.test.tsx
│   ├── Button.stories.tsx
│   └── index.ts
└── Card/
    ├── Card.tsx
    ├── CardHeader.tsx
    ├── CardBody.tsx
    ├── index.ts
    └── Card.test.tsx

Resources

  • Use composition over deep nesting
  • Keep components focused (single responsibility)
  • Prefer named exports for discoverability
Weekly Installs
1
First Seen
9 days ago
Installed on
claude-code1