Architecture at a Glance
Apollion is a React component library, but the folder it lives in is the first thing worth understanding — it's the contract every other doc on this site assumes.
One folder per component, one shape per folder
Every component owns a directory under src/<group>/<Component>/ with the
same five files, always:
Button/
├── Button.tsx # the component
├── Button.interface.ts # public prop types + TSDoc
├── Button.style.ts # styled-components, factory composition
├── Button.story.tsx # Storybook playground
├── Button.test.tsx # Jest — snapshot + logic asserts
└── README.mdx # this page's sibling — the "when to use" guideButton
is the canonical reference — when in doubt about a pattern, that's the
component to read.
Zero business logic
Components are purely visual. No fetch, no dispatch, no domain-specific
formatting, no validation beyond what the DOM element itself enforces. A
Button doesn't know what clicking it does; a Form orchestrates
react-hook-form + zod, but the schema and the submit handler are yours.
Composition over configuration
Complex UI comes from composing simple primitives, not from mega-components
with a hundred boolean props. Table is Table → TableHeader/TableBody
→ TableRow → TableCell — HTML-shaped, not opaque. Form is Form →
Field → Input. Card exposes named slots (media/title/description/
actionComponent) instead of children order that breaks on refactor.
See Composition for the deeper rule: most
wrapper <Flex>s in a screen are unnecessary — a leaf component is already a
flex container, and layout props belong on the leaf, not on a <div> built
just to hold them.
Three documentation layers, always co-resident
Every component ships three views of the same truth, in the same folder, committed in the same PR:
- TSDoc in the
.tsx/.interface.ts— the technical reference, consumed by your IDE and by AI coding agents. - Storybook (
.story.tsx) — an interactive visual playground. - MDX (
README.mdx) — the semantic "when to use / when not to" guide with live demos, which is what renders on this site.
Nothing is generated from nothing: docs drift is caught in CI, not discovered by a confused consumer six months later.
Naming carries the intent
Files are named so the intent is obvious without opening them — a
Button.style.ts is always the styled-components layer, a .interface.ts
is always the public prop contract. Comments explain why, not what; the
filename already says what.
See also
- Composition — when a wrapper is real, and when it's noise.
- Layout Props — the shared prop set every component accepts.
- Vendor Isolation — how third-party libraries stay swappable.