react-ts-rules
A React + TypeScript .claude/rules pack: strict-TS standards, component and variant patterns, and server-state data-fetching discipline (React Query, forms, auth).
The React and TypeScript layer that sits on top of the generic pack. Drawn from a production React 19 and Vite SPA, generalized so the rules hold whatever your folder layout is.
What's inside
ts-standards.md: strict mode with noany, alias imports, naming and file conventions, named-exports-only, and the two client-side security tells (no secrets in the bundle, no unsanitizeddangerouslySetInnerHTML).react-patterns.md: props-and-variant patterns (as constmaps,cn()merging), composition over rebuild, the mandatory loading, error, and empty async states, schema-first forms, and accessibility basics.data-fetching.md: one tool for server state, check-before-use, query-key factories, hook naming, mutations that invalidate and toast, and httpOnly-cookie auth overlocalStoragetokens.
How to use
Download and drop the .md files into .claude/rules/ alongside the generic pack. They load whenever you touch a .ts or .tsx file. Adjust the import-alias and folder references to your project.
Want these tuned to your actual codebase? Run /a-rules-optimizer from the dev-workflow-forge plugin.
data-fetching.md
---
paths:
- "**/*.ts"
- "**/*.tsx"
---
# Data Fetching
Layers on the TypeScript standards. Assumes a server-state library (React Query / TanStack Query); the discipline transfers to SWR.
## One Tool for Server State
- A server-state library is the only tool for fetching, caching, and syncing server data. Don't also keep server data in a global client-state store (Redux, Zustand, Jotai). Local UI state (modals, filters, toggles) stays in `useState` or `useReducer`.
## Check Before You Use
- If your API wraps responses (`{ success, data, error }`), check `success` and throw on failure before returning `data`. The query function returns the inner payload, not the envelope.
## Query Key Factory
- Give each domain a flat query-key factory so invalidation stays consistent:
```ts
export const userKeys = {
all: ['users'] as const,
list: (f: UserFilters) => [...userKeys.all, 'list', f] as const,
detail: (id: string) => [...userKeys.all, 'detail', id] as const,
};
```
## Hook Naming
- Fetch list `use<Resource>s()`, fetch one `use<Resource>(id)`, mutate `useCreate/Update/Delete<Resource>()`.
## Mutations
- On success: invalidate the queries the mutation affects, then show a success toast.
- On error: show the error toast. Never let a failed mutation fail silently.
## Auth Tokens
- Prefer an httpOnly cookie the browser sends automatically over a token in `localStorage`. A JS-readable token is an XSS payload's first prize.
- Keep a separate JS-readable, non-sensitive flag if the SPA needs to know it's logged in; the actual credential stays httpOnly.
react-patterns.md
---
paths:
- "**/*.tsx"
---
# React Component Patterns
Layers on the TypeScript standards.
## Props and Variants
- Define a `ComponentNameProps` interface. Destructure known props and accept an optional `className` for overrides.
- Type variants against a `const` object: `const variants = { success: '...', danger: '...' } as const`, then `variant: keyof typeof variants`. One source of truth for the allowed values.
- Merge class names with a helper (`clsx` plus `tailwind-merge`, exposed as `cn()`), not string concatenation.
## Composition
- Use your primitive or UI library for form controls, dialogs, sheets, and dropdowns. Don't rebuild a select from scratch.
- Extract a shared component once a pattern repeats three times, not before.
## The Three Async States (mandatory)
Never render a data view without handling all three states. A blank screen while loading is a bug.
```tsx
if (isLoading) return <LoadingState />;
if (error) return <ErrorState message="Failed to load" onRetry={refetch} />;
if (!data.length) return <EmptyState />;
return <DataDisplay data={data} />;
```
## Forms
- Schema-first validation (Zod or equivalent) bridged to the form library (React Hook Form via `zodResolver`).
- Always show inline field-level errors, not just a top-level "something went wrong".
## Accessibility
- Every icon-only button needs an `aria-label`.
- Every modal traps focus (most primitive libraries handle this; verify it).
- Interactive elements get a visible focus state and press feedback.
ts-standards.md
--- paths: - "**/*.ts" - "**/*.tsx" --- # TypeScript Standards Layers on the generic code-quality and architecture rules. Written for a React SPA, but the TypeScript rules hold for any TS project. ## TypeScript - Strict mode on. No `any`. Reach for `unknown` and narrow, or write the real type. - Absolute imports via a path alias (for example `@/`), not long `../../../` chains. - Domain-scoped type files (`types/user.ts`, `types/billing.ts`), not one giant `types.ts`. ## Naming - Types and interfaces: `PascalCase` (`User`, `CreateClassInput`). - Component props interface: `ComponentNameProps`. - When consuming an API, match the backend's field names rather than silently renaming, so the payload and the type line up. ## File Naming - Components `kebab-case.tsx`, pages `<name>-page.tsx`, hooks `use-<name>.ts`, types `<domain>.ts`, utils `<name>.ts`. Pick one convention and hold it. ## Import Order 1. React and external libraries 2. UI primitives 3. Custom components 4. Feature modules 5. Hooks, lib, types 6. Relative (sibling) imports ## Exports - Named exports only. No `export default`. Default exports make renames lossy and hurt auto-import. - One component per file for page-level components; a small helper component can share the parent file. ## Client-Side Security - The client bundle is public. Never put an API secret, private key, or server-only token in code that ships to the browser. - Don't set `dangerouslySetInnerHTML` from any value that isn't statically known or run through a sanitizer. It is the one place React stops escaping for you.
Everything mine on this shelf comes from my own working setup, shared for learning. Test it and adapt it to your project before relying on it; you run it at your own risk.