UI Page Structure
Purpose
Keep route-level code predictable: entry files, page-only components (and hooks), tests, and helpers live together. Enforce logic/JSX separation, require tests, and document with a README when the structure settles. Shared UI stays in src/components.
Rules (short)
- •Route entry:
src/pages/<route>/index.tsxexports the page component. - •Tiny single-file exception: keep
src/pages/<route>.tsxwhen the page is small and has no page-local components/hooks/tests/types/utils; once any co-located file is needed, move tosrc/pages/<route>/. - •Page-only UI + hooks:
src/pages/<route>/components/*(hooks live with related components; no standalonehooks/dir). - •Types + utils: colocate in the route folder (
types.ts,utils.ts, etc.). - •Logic vs JSX: keep logic in hooks/logic files, JSX in components (details below).
- •Extraction trigger: if route
index.tsxhas more than oneuseEffector includes direct IPC/file-system/network orchestration, extract a single page-local orchestration hook before adding more behavior. - •Tests: add enough to give confidence the page works; keep scope tight (no over-engineering).
- •Shared UI: only in
src/components(cross-page only). - •Avoid “sections” folders: page sections are just components.
- •README required: when structure is settled, add page README per
ui-page-readme(can be after-the-fact). - •Composition + React patterns: follow
vercel-composition-patternsandvercel-react-best-practiceswhen shaping component APIs and hook usage.
Recommended layout
code
src/pages/settings/
index.tsx
README.md
types.ts
utils.ts
components/
settings-account.tsx
settings-apps.tsx
settings-storage.tsx
settings-about.tsx
index.test.tsx
code
src/pages/runs/
index.tsx
README.md
components/
run-item.tsx
use-run-item.ts
utils.ts
index.test.tsx
Logic vs JSX (practical split)
- •Components render; hooks compute.
- •Components should be mostly JSX + light glue (props, callbacks, formatting).
- •Components must not fetch, mutate, or read storage/network directly.
- •Logic-only files (
use-*.ts,*logic.ts,*utils.ts) should not contain JSX or createReactNodes. - •Container/presenter split: page entry/containers call hooks, pass data to presentational components.
- •Hooks live with components when tightly coupled; keep pure logic separate to avoid merge conflicts.
- •Prefer composition over boolean prop modes; make explicit variants when behavior diverges.
- •State in providers/hooks; UI reads from hooks and renders.
Hook placement heuristic
- •Route-level hooks: routing, store, auth, network, or multi-component orchestration live at the
route root (
src/pages/<route>/). - •Component-level hooks: logic only used by a single component lives next to that component
(use
components/<component>/when a component grows). - •Root hook cap: keep 1-3 hooks at the route root; if you need more, split by component folder.
Tests (minimum bar)
- •
index.test.tsxcovering critical wiring and one or two key UI states. - •Add hook/component tests where behavior is non-trivial or risk-prone.
- •If runtime capability changes behavior (for example desktop/Tauri vs browser), include at least one test for each branch.
- •Avoid snapshots; assert behavior and side effects.
- •Follow
react-testingfor test scope, commands, and reporting.
Notes
- •Keep imports direct (avoid barrel files).
- •Prefer
@/path alias over long relative imports.