Claude Code Plugins

Community-maintained marketplace

Feedback

Build React SPAs where components are declarative UI consuming external state (Zustand/XState/TanStack Query). Logic lives in stores, not components.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name react
description Build React SPAs where components are declarative UI consuming external state (Zustand/XState/TanStack Query). Logic lives in stores, not components.

React Expert

Core Philosophy

Components consume external state, contain no logic:

  • External hooks at top (Zustand, XState, TanStack Query)
  • No useState/useReducer/useEffect for complex logic
  • Inline actions unless repeated 2+ times
  • Test stores/machines (unit tests), not components (E2E only)

State Management Stack

State Type Solution
Remote (REST) TanStack Query
Remote (GraphQL) Apollo Client
Application state Zustand
Complex machines XState
Local UI state useState (rare, last resort)

Component Pattern

// ✅ External hooks → Early returns → JSX
function UserProfile({ userId }: { userId: string }) {
  const { user, isLoading } = useUser(userId);
  const { updateProfile } = useUserActions();

  if (isLoading) return <Spinner />;

  return (
    <div>
      <h1>{user.name}</h1>
      <button onClick={() => updateProfile({ email: 'new@example.com' })}>
        Update
      </button>
    </div>
  );
}

Testing: Stores, Not Components

What Tool Why
Zustand stores Vitest Test without React
XState machines Vitest Deterministic transitions
Critical flows Playwright Real browser
Components Never Logic should be in stores
// Test store directly
const { login } = useAuthStore.getState();
await login({ email: 'test@example.com', password: 'pass' });
expect(useAuthStore.getState().user).toBeDefined();

Unique Patterns

Prop Ordering: Simple → Complex

<Table
  data={items}
  loading={isLoading}
  sortable
  onSort={handleSort}
  renderRow={(item) => <Row>{item.name}</Row>}
/>

Inline Props for Type Inference

// ✅ Inline - TypeScript infers types
<SearchableList
  items={budgets}
  renderItem={(budget) => <Card name={budget.name} />}
/>

// ❌ Extract only if repeated 2+ times
const renderItem = (budget: Budget) => <Card name={budget.name} />

Pattern Matching for Variants

import { match } from "ts-pattern"

{match(state)
  .with({_tag: "loading"}, () => <Spinner />)
  .with({_tag: "success"}, (s) => <Data value={s.data} />)
  .exhaustive()}

Performance: Profile First

Technique When
useMemo Profiled as slow
useCallback Repeated 2+ times
React.memo Props rarely change
Code splitting Route-level

Styled-Components: Consolidate with CSS Selectors

// ✅ Single component with CSS selectors
const Table = styled.table`
  thead { background: ${p => p.theme.colors.header}; }
  tbody tr:hover { background: ${p => p.theme.colors.hover}; }
  td { padding: ${p => p.theme.space.md}; }
`;

// ❌ Separate components for each element
const TableHeader = styled.thead`...`;
const TableRow = styled.tr`...`;
const TableCell = styled.td`...`;