Layout Props
Every @apollion-dsi/core component accepts a common set of layout
props — spacing, color, flex, size, border and typography — in addition
to the props specific to each component. They're declared as data right in
the JSX, with no hand-written CSS.
These props are shared by every component. Each component's Properties table lists only its specific API — the layout props below aren't repeated there.
Spacing
margin and padding accept the theme's scale tokens (xs, small,
medium, large, xl). Axis and side shortcuts:
| Prop | Effect |
|---|---|
m, mt, mr, mb, ml | margin (all / top / right / bottom / left) |
mx, my | margin horizontal / vertical |
p, pt, pr, pb, pl | padding (all / top / right / bottom / left) |
px, py | padding horizontal / vertical |
gap | space between children (on Flex/Grid) |
p="small"
p="medium"
p="large"
<Paper p="large" mb="medium" gap="small">
…
</Paper>Color and surface
| Prop | Effect |
|---|---|
color | text/content color (semantic or foundation token) |
readable | text intent: makes color legible (WCAG) against the theme's surface; true = AA, a number = custom floor |
bgColor | background color |
deep | elevation/surface level (0–n) |
deepColor, contrast | fine-tuning of surface and contrast |
color and bgColor also accept a runtime CSS color (#hex, rgb(),
oklch(), var(--*), currentColor) for external-data cases — a per-entity
palette from an API, a consumer CSS variable. The value passes through
untouched. Prefer theme tokens whenever the color is a design decision:
runtime values bypass the theme's contrast guarantees (readable still
applies if you set it explicitly).
Flex
Available on any Flex-based container (Flex, Paper, Card):
| Prop | Effect |
|---|---|
flexDirection | row / column (+ -reverse) |
alignItems, justifyContent | cross-axis / main-axis alignment |
alignContent | packing of wrapped lines |
gap | space between children |
grow, shrink, flex, flexBasis | flex sizing |
wrap, order | line wrapping and order |
alignSelf, justifySelf | the item's own alignment |
<Flex flexDirection="row" wrap="wrap" justifyContent="between" alignItems="center" gap="small">
…
</Flex>Alignment gotchas:
Flex'sflexDirectiondefault iscolumn(not CSS'srow) — for a row, declarerowexplicitly. On that default column, vertical centering isjustifyContent="center"(main axis);alignItemsis the cross axis (horizontal). Tokens are semantic (start,between); the native names (flex-start,space-between) are accepted as aliases, and an unknown value warns in development instead of silently emitting nothing. With mixed typography on the same line (a large value + a small suffix),alignItems="center"centers the line boxes and looks crooked; usealignItems="baseline"to align on the baseline.gap={0}is valid and zeroes the space between children.
Container queries — the cq channel
Viewport prefixes answer "how wide is the viewport"; cq answers "how wide
is my slot". Mark the slot with containment, then any child
adapts to the slot's width with the same factory props, per
theme.containerSizes key (xs 240 · sm 360 · md 480 · lg 640 · xl 900, a
separate scale from viewport breakpoints — slot widths are not viewport
widths):
<Flex containment="inline-size">
<Card cq={{ sm: { p: 'large' }, md: { flexDirection: 'row' } }} />
</Flex>Mobile-first applies here too: the base style IS the narrow-slot style and
wider slots opt in via ascending min-width container queries. Card is
already a size container — content inside a Card can use cq with no extra
wrapper. Never mark page-level shells (GlobalStyle, layout roots) as
containers — containment belongs on the immediate wrapper of the adapting
component.
The full story — the mental model, the
containmentmarker, thecontainerSizesscale, wherecqstops and JS begins, and how to explore it in Storybook — lives in Container Queries.
Grid
Grid configures columns/areas per breakpoint via medias:
<Grid medias={{ xs: { columns: '1fr' }, md: { columns: '1fr 2fr', areas: '"a b"' } }}>…</Grid>columns also accepts a typed auto-repeat object — the zero-media-query
card grid (tracks wrap by container width, minimum guarded with
min(<min>, 100%) so it never overflows a narrow viewport):
<Grid medias={{ xs: { columns: { autoFit: '250px' }, gap: 'medium' } }}>…</Grid>Alignment is part of the grid surface — on the host and per breakpoint —
with the same tokens as Flex: alignItems, justifyContent,
alignContent, plus grid-only justifyItems and placeItems. Centering a
cell's content needs no nested Flex:
<Grid
height="100%"
alignItems="center"
justifyItems="center"
medias={{ md: { columns: '1fr 1fr', placeItems: 'start' } }}
>
…
</Grid>Size
width, height, minWidth, maxWidth, minHeight, maxHeight — accept
tokens, numbers (px) or CSS strings ('100%', '24rem').
Position and display
| Prop | Effect |
|---|---|
display | flex, block, grid, none… |
position, top, right, bottom, left, zIndex | positioning |
transform | CSS string ('translate(-50%, -33px)') — recenter an anchored overlay |
overflow, overflowX, overflowY | overflow control |
cursor, isHidden, absoluteFill, truncate | common utilities |
Border and radius
| Prop | Effect |
|---|---|
borderColor, borderStyle, borderWidth, borderPosition | border |
borderRadius, round, square | radius (per-corner shortcuts: roundTop, sharpBottomLeft…) |
Typography
fontFamily, fontSize, fontWeight, fontStyle, lineHeight,
letterSpacing, textAlign, textTransform, textDecoration,
whiteSpace, wordBreak — accept tokens from the theme's typographic
scale.
legibility="on-photo" applies a reading shadow for text over a
photographic/illustrated background (a closed preset — not a free-form
textShadow).
Responsive
Any prop above accepts per-breakpoint variants with the sm_, md_, lg_
and xl_ prefixes (mobile-first — the unprefixed version is the default):
<Flex flexDirection="column" md_flexDirection="row" wrap="wrap" gap="small" md_gap="large">
…
</Flex>Where these props belong
Knowing how to declare spacing and alignment is half the job; the other
half is deciding which element they live on. An Apollion leaf component
is already a flex container, so most of a screen's Flexes are wrappers
that can disappear — with the spacing moving onto the child itself.
The full rule, the table of which props each leaf accepts, and the audit checklist live in Composition.
// bad — Flex exists only to carry the mb
<Flex mb="medium">
<Button text="Save" />
</Flex>
// good — the spacing lives on the Button itself
<Button text="Save" mb="medium" />