react-feature
vndee/engineering-skills/.claude/skills/react-feature/SKILL.md
Use when implementing a new React feature, page, component, or hook in a Vite/Bun frontend with testing-library
Skill3 starsChanged 7 months ago
What's in it
- React Feature Development
- Overview
- When to Use
- Feature Module Structure
- Component TDD
- Custom Hook Testing
- API Mocking with MSW
- State Patterns
- Loading/Error/Empty States
- Accessibility Checklist
- Chains
---
name: react-feature
description: Use when implementing a new React feature, page, component, or hook in a Vite/Bun frontend with testing-library
---
# React Feature Development
## Overview
TDD workflow for React features using Vitest + testing-library. User-centric testing with MSW for API mocking.
**Core principle:** Test what users see and do, not implementation details.
## When to Use
- Adding a new page or feature module
- Building reusable components
- Creating custom hooks
- Implementing forms, data fetching, or state management
## Feature Module Structure
```
src/features/users/
components/
UserList.tsx
UserList.test.tsx
UserForm.tsx
UserForm.test.tsx
hooks/
useUsers.ts
useUsers.test.ts
api/
users.ts
types/
index.ts
index.ts # public API barrel export
```
## Component TDD
**Test first:**
```tsx
// UserList.test.tsx
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { UserList } from './UserList'
describe('UserList', () => {
it('renders users', () => {
render(<UserList users={[{ id: '1', name: 'Alice', email: 'a@b.com' }]} />)
expect(screen.getByText('Alice')).toBeInTheDocument()
})
it('calls onDelete when delete button clicked', async () => {
const onDelete = vi.fn()
const user = userEvent.setup()
render(<UserList users={[{ id: '1', name: 'Alice', email: 'a@b.com' }]} onDelete={onDelete} />)
await user.click(screen.getByRole('button', { name: /delete/i }))
expect(onDelete).toHaveBeenCalledWith('1')
})
})
```
## Custom Hook Testing
```tsx
import { renderHook, waitFor } from '@testing-library/react'
import { useUsers } from './useUsers'
import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
function wrapper({ children }: { children: React.ReactNode }) {
return <QueryClientProvider client={new QueryClient()}>{children}</QueryClientProvider>
}
it('fetches users', async () => {
const { result } = renderHook(() => useUsers(), { wrapper })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(result.current.data).toHaveLength(2)
})
```
## API Mocking with MSW
```tsx
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/v1/users', () => {
return HttpResponse.json({
data: [{ id: '1', name: 'Alice', email: 'a@b.com' }],
})
}),
]
// src/mocks/server.ts
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)
// vitest.setup.ts
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
```
## State Patterns
| Pattern | When |
|---------|------|
| `useState` | Local component state |
| `useReducer` | Complex state transitions |
| React Query | Server state (fetching, caching) |
| Context | Shared UI state (theme, auth) |
| URL params | Filters, pagination, selected tab |
## Loading/Error/Empty States
Always handle all three:
```tsx
if (isLoading) return <Skeleton />
if (error) return <ErrorMessage error={error} onRetry={refetch} />
if (data.length === 0) return <EmptyState message="No users found" />
return <UserList users={data} />
```
## Accessibility Checklist
- Interactive elements have accessible names (aria-label or visible text)
- Forms have associated labels
- Error messages linked with aria-describedby
- Keyboard navigation works (Tab, Enter, Escape)
- Focus management after dynamic changes
## Chains
- **REQUIRED:** Invoke `superpowers:test-driven-development`
- **REQUIRED:** Follow `code-quality` standards — virtualize long lists, debounce inputs, paginate API calls, code-split routes
- **REQUIRED:** Update CLAUDE.md if new conventions, commands, or patterns are introduced (`claude-md`)
- Can develop in parallel with `go-feature` or `py-feature`
More agent context in vndee/engineering-skills
36 other files this repository gives its agents.
Skill
- adr.claude/skills/adr/SKILL.md
- analytics.claude/skills/analytics/SKILL.md
- api-contract.claude/skills/api-contract/SKILL.md
- api-design.claude/skills/api-design/SKILL.md
- ci-pipeline.claude/skills/ci-pipeline/SKILL.md
- claude-md.claude/skills/claude-md/SKILL.md
- code-quality.claude/skills/code-quality/SKILL.md
- data-model.claude/skills/data-model/SKILL.md
- db-migrate.claude/skills/db-migrate/SKILL.md
- debug.claude/skills/debug/SKILL.md
- deploy.claude/skills/deploy/SKILL.md
- dep-update.claude/skills/dep-update/SKILL.md
- disk-cleanup.claude/skills/disk-cleanup/SKILL.md
- docker-build.claude/skills/docker-build/SKILL.md
- eng-lead.claude/skills/eng-lead/SKILL.md
- event-driven.claude/skills/event-driven/SKILL.md
- fullstack-healthcheck.claude/skills/fullstack-healthcheck/SKILL.md
- go-feature.claude/skills/go-feature/SKILL.md
- go-integration-test.claude/skills/go-integration-test/SKILL.md
- go-refactor.claude/skills/go-refactor/SKILL.md
- go-scaffold.claude/skills/go-scaffold/SKILL.md
- incident-response.claude/skills/incident-response/SKILL.md
- interactive-clarify.claude/skills/interactive-clarify/SKILL.md
- observability.claude/skills/observability/SKILL.md
- onboarding.claude/skills/onboarding/SKILL.md
- product-spec.claude/skills/product-spec/SKILL.md
- py-feature.claude/skills/py-feature/SKILL.md
- py-integration-test.claude/skills/py-integration-test/SKILL.md
- py-migrate.claude/skills/py-migrate/SKILL.md
- py-refactor.claude/skills/py-refactor/SKILL.md
- py-scaffold.claude/skills/py-scaffold/SKILL.md
- react-refactor.claude/skills/react-refactor/SKILL.md
- react-scaffold.claude/skills/react-scaffold/SKILL.md
- review-code.claude/skills/review-code/SKILL.md
- security.claude/skills/security/SKILL.md
- system-design.claude/skills/system-design/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

