Component Decomposition
MANDATORY pattern for frontend files exceeding 600 lines. Splits complex components into focused modules with clear responsibilities.
Split Pattern
| Module | Contains | React Imports |
|---|---|---|
fooService.ts | Pure functions, constants, types | None |
useFooState.ts | State, queries, mutations, handlers | Yes (custom hook) |
FooSection.tsx | Presentational UI (props + useTranslation) | Yes (minimal) |
Foo.tsx | Orchestrator (calls hook, composes sections) | Yes |
Real Examples
| Domain | Directory | Files |
|---|---|---|
| Document Obtaining | frontend/src/components/document-obtaining/ | 60 |
| Form Builder | frontend/src/components/form-builder/ | 30 |
| Building Components | frontend/src/components/building-components-redesign/ | 18 |
| Invoices | frontend/src/components/invoices/ | 16 |
Typical Decomposition
components/invoices/
InvoiceList.tsx # Orchestrator
useInvoiceListState.ts # Queries, mutations, handlers
InvoiceTable.tsx # Presentational table
InvoiceFilters.tsx # Filter UI section
invoiceService.ts # Helpers, formatters, types
Component Library
Shared UI primitives live in frontend/src/components/ui/ (102 Shadcn/Radix components). These are presentational by definition and do not need decomposition.
New components/ui/ components MUST have .stories.tsx files (CSF3, tags: ['autodocs']).
Rules
- Orchestrator (
Foo.tsx): calls the custom hook, passes data down to sections. No direct API calls. - Custom hook (
useFooState.ts): all React Query usage, mutations, and event handlers. - Sections (
FooSection.tsx): receive props, render UI. Only hook allowed isuseTranslation. - Service (
fooService.ts): zero React imports. Pure TypeScript functions and types.
See Also
- Frontend Architecture — overall frontend structure
- Component Library — shared UI components
- State Management — choosing the right state tool
- React Query Pattern — server state in custom hooks
- Hooks — hook organization