File and folder structure
Composition over duplication
When you find yourself copying JSX, extract:<Button>, <Card>, <Input>) for UI atoms; extract domain-specific components (<TaskRow>, <UserAvatar>) into components/{domain}/.
Prop drilling vs. context
Three-deep prop passing is fine. Five-deep is the point to consider context.Use props for data
Anything that changes per render — list items, form values, IDs.
Use context for ambient state
Theme, current user, active workspace. Things that rarely change but are read everywhere.
Use Convex queries for server state
Don’t hand-roll a server-state context.
useQuery is the cache.Use Zustand for ephemeral UI state
Modal open/closed, sidebar collapse, multi-step form draft. State that doesn’t need to live in the URL or DB.
When to extract
- 3+ uses of the same JSX: extract a component.
- 5+ lines of JSX inside a JSX expression: probably extract.
- A
useEffectwith non-trivial logic: extract a custom hook.
Naming
- Components:
PascalCase. Files match the component (TaskRow.tsxexportsTaskRow). - Hooks:
useCamelCase. Files match (useDebouncedValue.ts). - Utilities:
camelCase. Files often grouped (utils/format.ts).
Tips
Related
State management
Where to put state.
shadcn/ui components
The primitive library.
Components panel
Browse and reuse.
