Copilot Instructions for Frontend Codebases
Frontend conventions for Copilot: a strict component file layout, an explicit decision tree for where state lives, and one CSS approach instead of three competing ones.
Use when: Use in a React + TypeScript frontend when Copilot keeps inventing new state patterns, inline styles, and 400-line components that mix data fetching with markup.
The skill file
GitHub Copilot · .github/copilot-instructions.md.github/copilot-instructions.md2945 chars
# Frontend Instructions
## Component structure
- One component per file, named export matching the filename: `UserMenu.tsx` exports `UserMenu`. No default exports.
- File order inside a component module: types/interfaces, the component, subcomponents used only here, helpers, constants. Hooks extracted from the component go in a sibling `useUserMenu.ts` once they exceed ~15 lines.
- Components over ~150 lines must be split. Extract by responsibility (data vs. presentation), not by "top half / bottom half".
- Props interfaces are named `<Component>Props` and declared in the same file. Never use `React.FC` — type the props parameter directly.
- Data fetching happens in route loaders or query hooks, never inside presentational components. A component that receives data via props must not also fetch it.
- Lists render with stable IDs as keys — array indices as keys are forbidden.
## State management decision tree
Choose in this order; do not skip levels:
1. Derivable from existing props/state? Compute it inline — no state at all.
2. Used by one component? `useState` in that component.
3. Shared by a parent and 1–2 children? Lift to the nearest common parent.
4. Server data (anything fetched)? It belongs to the query cache (TanStack Query) — never copy server responses into `useState`.
5. URL-worthy (filters, tabs, pagination, search)? Put it in the URL search params, not component state.
6. Truly global client state (theme, auth session, feature flags)? One small store (Zustand) or context — and adding a new global store slice requires justification in the PR description.
- `useEffect` is for synchronizing with external systems only (DOM APIs, subscriptions, analytics). Never use it to derive state from other state or to "react" to a prop change you could compute.
## CSS approach
- Tailwind utility classes are the only styling mechanism. No CSS modules, no styled-components, no inline `style={{}}` except for values computed at runtime (e.g. dynamic transforms).
- Use design tokens (`bg-surface`, `text-muted`) defined in the Tailwind config — raw palette values like `bg-[#1a1a2e]` or `text-gray-500` are forbidden.
- Conditional classes go through the `cn()` helper, never template-string concatenation.
- Spacing comes from parents: components do not carry outer margins; layout containers apply `gap`/`space-y`. A reusable component with `mt-6` baked in is a bug.
- Responsive styles are mobile-first (`md:`, `lg:` to scale up); never write desktop-first overrides.
## Quality bar
- Every interactive element is a real `<button>` or `<a>` — no `onClick` on `div`s. Images require `alt`; form inputs require an associated label.
- Loading and error states are explicit JSX branches, not omitted. Empty states get real copy, not a blank container.
- Run `npm run lint` and `npm run typecheck` before suggesting a commit; component logic changes need a matching test update in the co-located `*.test.tsx`.
Install
drop into your repoSave this to your project or home directory so GitHub Copilot can load it.
path./.github/copilot-instructions.md
Discussion
What people are saying
Forks
0 forks of this skillLoading forks…