Style Props

The design scale as typed props — spacing, color, radius and more on every layout primitive.

The idea#

Instead of writing CSS (or utility class strings) for everyday styling, you pass tokens as props:

<Box p="6" bg="subtle" rounded="xl" shadow="sm" maxW="md" />

Three things distinguish this from a style attribute:

  • Values come from the design scale, not free-form CSS — p="6" is the spacing token 6, bg="subtle" is a semantic color role. Consistency is the default, not a discipline.
  • Everything is typed. Your editor autocompletes valid values; p="7.5" is a compile error, not a silent oddity.
  • Every prop is responsive. Any value can be a breakpoint map — see Responsive Props.

Where style props live#

Box is the host — a polymorphic div exposing the full set. Every other layout primitive (Flex, Stack, Grid, Center, Container, AspectRatio, Float) extends Box, so all of them accept all of these props on top of their own. Typography components (Text, Heading) carry the relevant subset.

Higher-level components (Button, Card, Modal…) deliberately do not take style props — their look is the design system's job, adjusted through variant, size and colorScheme. For layout around them, wrap them in a Box.

The prop families#

PropTypeDefaultDescription
p · px · py · pt/pb/pl/pr"0.5" – "96" (spacing scale)Padding — all sides, per axis, or per edge.
m · mx · my · mt/mb/ml/mr"0.5" – "96" (spacing scale)Margin — all sides, per axis, or per edge.
w · h · size · minW/maxW · minH/maxHspacing scale | "xs"–"8xl" | fractions | "auto" | "full" | "fit" | "prose" …Sizing. size sets width and height at once.
bg"base" | "panel" | "subtle" | … | "{hue}-solid/subtle/muted/emphasized" | "{hue}-50"–"{hue}-950"Background from semantic roles, palette roles, or raw shades. Transparent by default.
color"base" | "muted" | "subtle" | "inverted" | status tokens …Text color token; children inherit it.
border · borderStyle · borderColor"normal"–"thickest" · CSS styles · "base" | "subtle" | "{hue}-stroke" …Border width, style and color tokens.
rounded (+ roundedT/R/B/L, corner variants)"none" | "2xs"–"4xl" | "full"Corner radius — all corners, per side, or per corner.
display"block" | "flex" | "grid" | "hidden" | …CSS display.
position · inset · top/right/bottom/left · zIndexposition tokens + offset scalePositioning.
shadow"none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "inner"Box shadow token.
opacity · overflow(X/Y) · cursor · pointerEvents · aspectRatiotoken mapsMisc utilities, all typed.
asElementType"div"Element or component to render; HTML props follow it type-safely.

Escape hatches#

When you need something outside the scale, drop down a level — in this order:

1. className — every component forwards it, and conflicts resolve predictably: your classes are merged last, so they win against the component's own styling.

<Box p="4" className="my-fancy-gradient" />

Your own utility classes work here too, whatever generates them — Astralis's internal classes are prefixed (astralis:*), so the two systems can't collide.

2. style — for truly dynamic one-off values:

<Box style={{ transform: `translateX(${offset}px)` }} />

3. Plain CSS — Astralis renders ordinary DOM elements, and every design token is a documented CSS variable, so your stylesheets can target components and stay on the scale:

.sidebar {
  padding: var(--astralis-spacing-6);
  background: var(--astralis-color-surface-subtle);
}

Why a closed scale?#

Astralis ships precompiled CSS — the stylesheet you import already contains every class these props can produce, verified by a build-time coverage gate. That's why the props accept tokens rather than arbitrary values: a fixed vocabulary is what makes it possible to guarantee, at build time, that every prop value actually has CSS behind it. Arbitrary values would need a runtime style engine — the exact cost the library is designed to avoid.