Skip to content
On this page Responsive values

Layout

Layout primitives

Box, Flex, Stack, Grid, Container and Section: spacing and alignment as token props, rendered as data attributes with no inline style.

<script>
  import { Stack, Flex, Grid, Box, Container, Section } from "@codeatlasdev/ui";
</script>

<Container size="md">
  <Section>
    <Stack as="ul" gap="4">…</Stack>
    <Grid columns={{ base: 1, md: 3 }} gap="4">…</Grid>
  </Section>
</Container>

Every primitive renders any element (as) and forwards class and other attributes. Box, Flex, Stack and Grid are typed on the tag: as="form" takes the form’s own attributes and handlers (novalidate, action, onsubmit with currentTarget: HTMLFormElement), as="a" takes href, as="label" takes for, and an attribute of another tag is a type error. A token prop never becomes inline CSS: it is a data-* attribute (<div data-gap="4">) styled by one stylesheet in @layer ca.utilities, so the markup is cache-friendly, passes a strict CSP, and an app can override any step with a plain class.

Primitive Renders Props
Box div, padding p, px, py
Flex display: flex gap, p, px, py, align, justify, direction, wrap
Stack a Flex column gap, p, px, py, align, justify
Grid display: grid, equal tracks columns, gap, p, px, py, align
Container centered, width-capped, fluid gutter size (sm md lg xl), px, py
Section a <section> with the page rhythm size (1 2 3), px, py

Spacing values are steps of the spacing scale as strings ("4" is --ca-space-4, 16px at the default density; "0.5" is 2px). The scale is 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 6 7 8 10 11 12 16 20 24. A value off the scale logs a [ca-ui] warning in development and renders unstyled: for a one-off value add a class.

align is start | center | end | stretch | baseline, justify is start | center | end | between | around | evenly, direction is row | column | row-reverse | column-reverse, and columns is 1 to 12 equal tracks. For a template like 2fr 1fr or repeat(auto-fill, minmax(200px, 1fr)) write grid-template-columns in a class.

Responsive values

Pass an object instead of a value. base applies everywhere, and each breakpoint applies from its width up, on the shared scale: sm 600, md 900, lg 1200, xl 1536 px. The object becomes data-gap="2" data-md-gap="4".

#182

Flex, Stack and Box

Flex, space between
gap 3
wraps
Stack gap 4, Box padding 4

Reference #182 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Stack, Flex, Box } from '@codeatlasdev/ui';
</script>

<Stack gap="4" p="4">
  <Flex gap="3" align="center" justify="between" wrap>
    <Box class="chip" px="3" py="1">Flex, space between</Box>
    <Box class="chip" px="3" py="1">gap 3</Box>
    <Box class="chip" px="3" py="1">wraps</Box>
  </Flex>
  <Box class="chip" p="4">Stack gap 4, Box padding 4</Box>
</Stack>

<style>
  :global(.chip) { background: var(--ca-surface-raised); border-radius: var(--ca-radius-md); box-shadow: inset 0 0 0 1px var(--ca-outline-subtle); font-size: var(--ca-font-size-body2); }
</style>
#181

Responsive Grid

Resize the window: 1, 2, then 4 columns, and the gap grows at `md`.

1
2
3
4
5
6
7
8

Reference #181 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Grid, Box } from '@codeatlasdev/ui';
</script>

<Grid columns={{ base: 1, sm: 2, lg: 4 }} gap={{ base: '2', md: '4' }} p="4">
  {#each [1, 2, 3, 4, 5, 6, 7, 8] as n (n)}
    <Box class="cell" p="4">{n}</Box>
  {/each}
</Grid>

<style>
  :global(.cell) { background: var(--ca-surface-raised); border-radius: var(--ca-radius-md); box-shadow: inset 0 0 0 1px var(--ca-outline-subtle); text-align: center; font-size: var(--ca-font-size-body2); }
</style>
#180

Container and Section

Starter

Up to 3 projects.

Team

Unlimited projects and roles.

Reference #180 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Container, Section, Stack, Card } from '@codeatlasdev/ui';
</script>

<Container size="md">
  <Section size="1" aria-label="Plans">
    <Stack gap="4">
      <Card title="Starter" headingLevel={3} material="solid">Up to 3 projects.</Card>
      <Card title="Team" headingLevel={3} material="solid">Unlimited projects and roles.</Card>
    </Stack>
  </Section>
</Container>

Shared props

PropTypeDefaultDescription
askeyof SvelteHTMLElementsper componentElement to render (`div`, `section`, `ul`, `form`...). Box, Flex, Stack and Grid also accept that element's own attributes and event types.
gapSpace | responsiveundefinedGap between children.
p, px, pySpace | responsiveundefinedPadding on every side, horizontal, vertical.
align'start' | 'center' | 'end' | 'stretch' | 'baseline' | responsiveundefined`align-items`.
justify'start' | 'center' | 'end' | 'between' | 'around' | 'evenly' | responsiveundefined`justify-content`.
direction'row' | 'column' | 'row-reverse' | 'column-reverse' | responsive'row'Flex only.
wrapboolean | responsivefalseFlex only: `flex-wrap: wrap`.
columns1–12 | responsiveundefinedGrid only: equal tracks.

Migrating from Stack, Grid and Row

Stack’s gap used to be pixels (gap={16}) and Grid took cols. They now take spacing steps (gap="4") and columns, and Row is deprecated in favor of Flex. Run the codemod, which converts every static usage and leaves the rest for you:

bunx @codeatlasdev/ui migrate --write src
Before After
<Stack gap={16}> <Stack gap="4">
<Stack align="flex-end" justify="space-between"> <Stack align="end" justify="between">
<Row gap={8} wrap> <Flex gap="2" wrap>
<Grid cols={3} gap={8}> <Grid columns={3} gap="2">
<Grid cols="2fr 1fr" gap={20}> <Grid cols="2fr 1fr" gap="5"> and a class with grid-template-columns: 2fr 1fr (cols is reported, the gap is still converted)

What the codemod cannot map is left as it was and listed at the end with file, line, reason and recipe, for example src/T.svelte:5 Grid: cols is a template string (write grid-template-columns in a class) or src/T.svelte:6 Stack: dynamic gap (use a step string: px / 4, e.g. gap={16} is gap="4"). A gap={gap} left untouched is not harmless: it is now a step, so 16 means 64px. Add --strict to exit with code 1 when anything was left (CI, scripts).