Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Keep component implementation files under 300 lines and colocated in their component folder
React component implementation files must stay under 300 lines, and the main component entry should live inside its own component folder. If hooks, effects, handlers, JSX, or hard-coded copy make a component grow, split the logic into hooks, child components, and dedicated constants/copy files instead of keeping one large TSX file or a stray sibling component file outside the folder.
Bad example
| 1 | // src/components/Header.tsx |
| 2 | export function Header() { |
| 3 | const [isOpen, setIsOpen] = useState(false); |
| 4 | const [activeTab, setActiveTab] = useState('overview'); |
| 5 | const [query, setQuery] = useState(''); |
| 6 |
|
| 7 | useEffect(() => { |
| 8 | // one effect |
| 9 | }, []); |
| 10 |
|
| 11 | useEffect(() => { |
| 12 | // another effect |
| 13 | }, [query]); |
| 14 |
|
| 15 | function handlePrimaryAction() {} |
| 16 | function handleSecondaryAction() {} |
| 17 |
|
| 18 | // imagine hundreds more lines of mixed hooks, handlers, JSX, and copy |
| 19 | return <header>{/* 300+ lines of mixed concerns */}</header>; |
| 20 | } |
| 21 |
|
| 22 | // src/components/Header/ |
| 23 | // HeaderActions.tsx |
| 24 | // hooks/use-header-state.ts |
| 25 | // header.copy.ts |
Explanation (EN)
This keeps the main component outside the folder that already owns its related files, and the component itself is oversized. Ownership becomes scattered across two locations and the implementation remains too large to read comfortably.
Objašnjenje (HR)
Ovo drzi glavnu komponentu izvan foldera koji vec sadrzi povezane fileove, a sama komponenta je i dalje prevelika. Ownership je rasprsen na dvije lokacije i implementacija ostaje prevelika za ugodno citanje.
Good example
| 1 | // src/components/Header/index.tsx |
| 2 | import { headerCopy } from './header.copy'; |
| 3 | import { useHeaderState } from './hooks/use-header-state'; |
| 4 | import { HeaderActions } from './HeaderActions'; |
| 5 | import { HeaderSearch } from './HeaderSearch'; |
| 6 |
|
| 7 | export function Header() { |
| 8 | const { isOpen, activeTab, query, handlers } = useHeaderState(); |
| 9 |
|
| 10 | return ( |
| 11 | <header> |
| 12 | <HeaderSearch query={query} onSearch={handlers.onSearch} /> |
| 13 | <HeaderActions |
| 14 | isOpen={isOpen} |
| 15 | activeTab={activeTab} |
| 16 | onPrimaryAction={handlers.onPrimaryAction} |
| 17 | onSecondaryAction={handlers.onSecondaryAction} |
| 18 | /> |
| 19 | <p>{headerCopy.footerNote}</p> |
| 20 | </header> |
| 21 | ); |
| 22 | } |
Explanation (EN)
The main component entry is colocated with its hooks, child components, and copy. The component stays focused on composition while related implementation details remain in the same folder.
Objašnjenje (HR)
Glavni entry komponente je colociran s hookovima, child komponentama i copyjem. Komponenta ostaje fokusirana na kompoziciju, a povezani detalji implementacije ostaju u istom folderu.
Notes (EN)
Treat this as one of the strictest frontend rules in the project. When a component starts collecting too many hooks, effects, handlers, conditional branches, or text blocks, refactor early instead of waiting for a large cleanup later. Prefer colocated hooks folders and nearby child components, and keep the main exported component entry inside that same component folder so ownership stays obvious.
Bilješke (HR)
Tretiraj ovo kao jedno od najstrozih frontend pravila u projektu. Kada komponenta pocne skupljati previse hookova, effecta, handlera, grananja ili tekstualnih blokova, refaktoriraj rano umjesto da cekas veliki cleanup kasnije. Preferiraj colocated hooks foldere i obližnje child komponente, a glavni export komponente drzi unutar istog component foldera kako bi ownership ostao jasan.
Exceptions / Tradeoffs (EN)
This limit applies to component implementation files, not every TypeScript file. Files that are mostly props, types, filter definitions, large option lists, copy dictionaries, mappings, config objects, or generated data may exceed 300 lines when that is the cleanest representation. Those exceptions do not justify oversized TSX component files, and they do not justify leaving the main component entry outside the folder that owns the rest of the component.
Iznimke / Tradeoffi (HR)
Ovo ogranicenje vrijedi za implementacijske component fileove, a ne za svaki TypeScript file. Fileovi koji su uglavnom propsi, tipovi, definicije filtera, veliki popisi opcija, copy dictionaryji, mappingi, config objekti ili generirani podaci mogu prijeci 300 linija kada je to najcistiji prikaz. Te iznimke ne opravdavaju prevelike TSX component fileove niti ostavljanje glavnog entryja komponente izvan foldera koji sadrzi ostatak komponente.