Skip to contentAsheeUIAsheeUI

Layout and spacing

The spacing scale, the width tokens, and the axis vocabulary every layout component shares.

The layouts are one system rather than twelve components: a spacing scale, a set of width tokens, and an axis vocabulary that Stack, Grid and Split express differently. Learn the three and you can read any of them.

The spacing scale

Every spacing, gap and minHeight in the layout family takes the same token, so a page's rhythm is a decision rather than a number typed in each place.

Token Steps of 0.25rem Use it for
none 0 A band that must sit flush against what follows
xs 1 (0.25rem) Icon-to-label, inside a chip
sm 2 (0.5rem) Between related lines
md 4 (1rem) The default gap between siblings
lg 6 (1.5rem) Between groups inside a band
xl 8 (2rem) Between bands
2xl 12 (3rem) A band that is meant to feel like a break

The token names are the API; the numbers are what the theme maps them to. A product that wants a tighter or looser page changes the scale once, not every call site.

Width

A width is one of five tokens, and it is a maximum rather than a fixed size: content narrower than the token still sits at its natural width, centred or aligned by its parent.

Token Behaviour
sm, md, lg, xl A maximum width with side gutters, so text does not run to the edge of a wide window
full No maximum: the band fills the viewport

Two props pair with it, and the pairing is what keeps a full-bleed band from being a design dead end: contained says whether the content inside is held to a width at all, and containerSize says which width. A band with contained={false} is full-bleed but its content may still be contained, that is what a coloured section with a centred headline is.

Asking for the width

A style is answered by a media query through a class, which is what every component uses. A branch — render a table or cards, a row of actions or an overflow menu — decides which elements exist, and a class cannot do that. useBreakpoint() is how a component asks, and both renderers export it under that name with the same shape:

import { useBreakpoint } from "asheeui";

const { width, breakpoint, isAtLeast } = useBreakpoint();

return isAtLeast("lg") ? <Table rows={rows} /> : <Cards rows={rows} />;

breakpoint is the largest name the width has reached, or base below the smallest, and the widths are @asheeui/core's BREAKPOINT (sm 640, md 768, lg 1024, xl 1280) on both platforms. The platform reads its window's own dimensions; the web measures the window after mount, so server-rendered markup is the narrow arrangement and hydration never mismatches.

The rule that turns a width into a name is exported as resolveBreakpoint, and the state's shape as BreakpointState, so a component that measures its own container can reuse both without importing a renderer. useReduceMotion() follows the same pattern: the reader's motion preference, under one name on either platform.

The as prop

Every layout component takes as, which changes the element it renders without changing what it does. That is how a page states its structure: as="header", as="nav", as="main", as="section". The default is always the sensible neutral element, so as is for stating meaning the component cannot infer, not for styling.

The axis vocabulary

Three components place children along an axis, and they use the same words for the same ideas:

Idea Stack Grid Split
How children flow direction (row, column) columns (1…12, at sm/md/lg breakpoints) Two panes, side by side above stackAt
Space between them gap gap gap
Cross-axis alignment align (start, center, end, stretch, baseline) align (start, center, end, stretch) align (start, center, stretch)
Main-axis distribution justify (start, center, end, between) ratio (equal, start, end)
When it wraps wrap Always, by column count At stackAt (sm, md, lg, xl)

The distinction worth holding on to: Stack is one-dimensional, a row or a column of things, in the order you write them. Grid is two-dimensional, a fixed number of columns, so the items that do not fit wrap onto the next line themselves. Split is two things, a pair that sits side by side when there is room and stacks when there is not, which is the shape of a settings panel, a comparison or a table of contents.

Which one for which job

The page needs Use
A row or column of items with a gap Stack
A wall of cards in equal columns Grid
Something beside something else, stacking on narrow screens Split
One thing in the middle of the viewport Centered
A band of a page with a heading and a width Section
A maximum width around arbitrary content Container
A whole page shell Page, SidebarLayout, DocsLayout, MarketingLayout

For how the shells assemble a real page, including which one a product should start from, see Page compositions.