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.tsx exports the page component.
- Tiny single-file exception: keep
src/pages/<route>.tsx when the page is small and has no page-local components/hooks/tests/types/utils; once any co-located file is needed, move to src/pages/<route>/.
- Page-only UI + hooks:
src/pages/<route>/components/* (hooks live with related components; no standalone hooks/ 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.tsx has more than one useEffect or 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-patterns and vercel-react-best-practices when shaping component APIs and hook usage.
Recommended layout
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
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 create ReactNodes.
- 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.tsx covering 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-testing for test scope, commands, and reporting.
Ownership moves
- If a route becomes the canonical owner of a feature surface, move both the page-owned UI surface and the page-level data-loading/readiness trigger in the same diff.
- Do not leave fetch ownership behind on a previously related route after UI ownership moves.
- When deciding whether two surfaces should share an implementation, compare user-facing actions first. Different actions mean different surfaces even if the rows or layout look similar.
URL-backed page state
- When adding URL-backed page state (for example tabs, filters, or modes), add non-mocked page tests for:
- param-to-state derivation on first render
- invalid-value fallback/canonicalization
- write/remove behavior that preserves unrelated search params
Notes
- Keep imports direct (avoid barrel files).
- Prefer
@/ path alias over long relative imports.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: ui-page-structure3description: Standardize DataConnect route/page layout, logic/JSX separation, tests, and README expectations. Use when organizing pages/routes, refactoring page structure, or discussing file structure conventions. Use when this capability is needed.4---56# UI Page Structure78## Purpose910Keep 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`.1112## Rules (short)1314- **Route entry**: `src/pages/<route>/index.tsx` exports the page component.15- **Tiny single-file exception**: keep `src/pages/<route>.tsx` when the page is small and has no page-local components/hooks/tests/types/utils; once any co-located file is needed, move to `src/pages/<route>/`.16- **Page-only UI + hooks**: `src/pages/<route>/components/*` (hooks live with related components; no standalone `hooks/` dir).17- **Types + utils**: colocate in the route folder (`types.ts`, `utils.ts`, etc.).18- **Logic vs JSX**: keep logic in hooks/logic files, JSX in components (details below).19- **Extraction trigger**: if route `index.tsx` has more than one `useEffect` or includes direct IPC/file-system/network orchestration, extract a single page-local orchestration hook before adding more behavior.20- **Tests**: add enough to give confidence the page works; keep scope tight (no over-engineering).21- **Shared UI**: only in `src/components` (cross-page only).22- **Avoid “sections” folders**: page sections are just components.23- **README required**: when structure is settled, add page README per `ui-page-readme` (can be after-the-fact).24- **Composition + React patterns**: follow `vercel-composition-patterns` and `vercel-react-best-practices` when shaping component APIs and hook usage.2526## Recommended layout2728```29src/pages/settings/30 index.tsx31 README.md32 types.ts33 utils.ts34 components/35 settings-account.tsx36 settings-apps.tsx37 settings-storage.tsx38 settings-about.tsx39 index.test.tsx40```4142```43src/pages/runs/44 index.tsx45 README.md46 components/47 run-item.tsx48 use-run-item.ts49 utils.ts50 index.test.tsx51```5253## Logic vs JSX (practical split)5455- **Components render; hooks compute.**56- **Components** should be mostly JSX + light glue (props, callbacks, formatting).57- **Components must not** fetch, mutate, or read storage/network directly.58- **Logic-only files** (`use-*.ts`, `*logic.ts`, `*utils.ts`) should not contain JSX or create `ReactNode`s.59- **Container/presenter split**: page entry/containers call hooks, pass data to presentational components.60- **Hooks live with components** when tightly coupled; keep pure logic separate to avoid merge conflicts.61- **Prefer composition** over boolean prop modes; make explicit variants when behavior diverges.62- **State in providers/hooks**; UI reads from hooks and renders.6364## Hook placement heuristic6566- **Route-level hooks**: routing, store, auth, network, or multi-component orchestration live at the67 route root (`src/pages/<route>/`).68- **Component-level hooks**: logic only used by a single component lives next to that component69 (use `components/<component>/` when a component grows).70- **Root hook cap**: keep 1-3 hooks at the route root; if you need more, split by component folder.7172## Tests (minimum bar)7374- `index.test.tsx` covering critical wiring and one or two key UI states.75- Add hook/component tests where behavior is non-trivial or risk-prone.76- If runtime capability changes behavior (for example desktop/Tauri vs browser), include at least one test for each branch.77- Avoid snapshots; assert behavior and side effects.78- Follow `react-testing` for test scope, commands, and reporting.7980## Ownership moves8182- If a route becomes the canonical owner of a feature surface, move both the page-owned UI surface and the page-level data-loading/readiness trigger in the same diff.83- Do not leave fetch ownership behind on a previously related route after UI ownership moves.84- When deciding whether two surfaces should share an implementation, compare user-facing actions first. Different actions mean different surfaces even if the rows or layout look similar.8586## URL-backed page state8788- When adding URL-backed page state (for example tabs, filters, or modes), add non-mocked page tests for:89 - param-to-state derivation on first render90 - invalid-value fallback/canonicalization91 - write/remove behavior that preserves unrelated search params9293## Notes9495- Keep imports direct (avoid barrel files).96- Prefer `@/` path alias over long relative imports.9798---99> Converted and distributed by [TomeVault](https://tomevault.io/claim/vana-com) — claim your Tome and manage your conversions.100<!-- tomevault:4.0:skill_md:2026-04-13 -->