Intent-driven layout primitives for the modern web.
Stop fighting CSS. Express what something is, not how it looks.
<Center measure='wide'>
<Stack gap='section'>
<Header />
<Grid min='md' gap='related'>
<Box pattern='card'>Revenue</Box>
<Box pattern='card'>Users</Box>
<Box pattern='card'>Growth</Box>
</Grid>
</Stack>
</Center>Semantic spacing — Use gap="related" instead of gap-4. Express relationships, not pixels.
Composable primitives — Small layouts that combine into any interface. Stack, Cluster, Grid, Center, Box.
Zero runtime — Pure CSS. Works with React, Vue, Svelte, or vanilla HTML.
~3KB gzipped — No dependencies. Ships what you need, nothing more.
npx joinery initThis adds the CSS files to your project. Import them:
@import './joinery/tokens.css';
@import './joinery/reset.css';
@import './joinery/primitives.css';Or use the React components:
npx joinery add reactimport { Stack, Grid, Box } from './joinery/react'| Primitive | Purpose |
|---|---|
| Stack | Vertical flow with consistent spacing |
| Cluster | Horizontal grouping that wraps |
| Grid | Auto-fit responsive columns |
| Center | Horizontally centered content |
| Box | Padding container with border/background |
| Token | Use for |
|---|---|
tight |
Icon + text, tightly coupled items |
related |
Items that belong together |
distinct |
Separate but grouped items |
section |
Major content divisions |
page |
Page-level separation |
<div class="stack" data-gap="related">
<h2>Title</h2>
<p>Description</p>
<button>Action</button>
</div><div class="cluster" data-justify="between">
<div class="logo">Brand</div>
<nav>Links</nav>
</div><div class="grid" data-min="md" data-gap="related">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div><div class="center" data-measure="wide">
<article>Centered content</article>
</div><div class="box" data-padding="distinct" data-pattern="card">Card content</div>Joinery is built on Every Layout principles:
- Style the context, not the element — Spacing belongs to containers, not children
- Be the browser's mentor, not its micromanager — Let CSS do what it does best
- Semantic intent over arbitrary values —
gap="related"communicates meaning
MIT