Foundations
Composition
StableFour levels, one rule: nothing at a higher level re-implements something from a lower one.
Updated in v1.0.0
The four levels
Foundry is organised as four levels of composition, and the only structural rule is that each level is built from the one below it.
- Primitives — 45 components that read tokens and nothing else.
- Navigation and forms — 38 navigation systems and 28 form flows, each an arrangement of primitives.
- Sections and patterns — 109 sections and 10 complete page compositions.
- Starters — 10 products spanning 109 concrete routes.
That constraint is what keeps 240 catalogued items coherent instead of merely numerous. It is also what makes the catalogue extensible: adding an item means adding a record and a file, never editing a page.
What counts as a variant
A variant is valid when it represents a real decision. Primary and destructive are variants, because choosing between them is a product decision. A button with four extra pixels of padding is not — that is a density token.
The same test applies at every level. Two sections that differ only in padding are one section; two that solve different layout problems are two. The variant list on every catalogue page is written to make that distinction explicit, and the test suite asserts that every item declares at least two.
How a section is built
Open the source on any section page. The imports at the top are the whole story: a section names the primitives it uses, arranges them, and reads its copy from src/content/. There is no section-local styling system and no section-local state.
Marketing copy lives outside the component on purpose. A section file should be a layout decision and nothing else, which is also what stops 109 sections becoming 109 copies of the same paragraph.
How a page pattern is built
A pattern is a fragment containing nine or ten imports. That is the entire file. Composing a page is choosing an order, and the composition playground makes that literal by putting the order in the URL.
How a starter is built
A starter is data. Each one declares a route table, and each route declares the catalogue blocks it composes. One dynamic route renders every page of all 10 products, which is why 109 routes cost one page component rather than 109 files.
It is also what makes the “no duplicated code between starters” claim structural rather than aspirational: there is nowhere to duplicate it. When a starter needs a screen no block covers — a cart, an admin table, an article body — that screen is written once in src/components/starter-kit/pages.tsx and shared.
Growing the catalogue
The architecture is designed to hold ten times its current size without a rewrite. Adding a component means adding a file and a catalogue record; the build step registers its source, the detail page renders it, search indexes it and the sitemap includes it. Adding a whole category means adding one entry to the family definition, and it appears in the filters, the search grouping and the footer automatically.
See Contributing for the exact steps.