Skip to main contentSkip to docs navigation

Compose flexbox properties into two one-dimensional layout primitives — Stack for vertical and horizontal arrangements, with responsive direction switching.

<Stack> composes flexbox properties into two layout primitives: direction="horizontal" (the default, wraps .hstack) for row arrangements and direction="vertical" (wraps .vstack) for column arrangements. The concept originates from the open source Pylon project.

For simple one-dimensional arrangements — a toolbar, a form's field list — <Stack> needs no grid around it. Reach for <Flex> instead for more control than Stack's fixed alignment defaults give — wrapping, main-axis justification, or no default alignment at all. Reach for <Grid> for responsive column spans, start lines, and two-dimensional row-and-column layouts.

A Tailwind build of @chassis-ui/css has the classes of gap only with its safelist loaded: see Tailwind.

Vertical

direction="vertical" arranges children in a column. Items stretch to full width by default; gap controls the spacing between them.

First item
Second item
Third item
JSX
import { Stack } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Stack direction="vertical" gap="md">
      <div className="p-xs">First item</div>
      <div className="p-xs">Second item</div>
      <div className="p-xs">Third item</div>
    </Stack>
  )
}

Horizontal

The default direction="horizontal" arranges children in a row, aligned to the start of the cross axis. Items take only their natural width; gap controls the spacing between them.

First item
Second item
Third item
JSX
import { Stack } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Stack gap="md">
      <div className="p-xs">First item</div>
      <div className="p-xs">Second item</div>
      <div className="p-xs">Third item</div>
    </Stack>
  )
}

.ms-auto acts as a spacer, pushing following items to the far end:

First item
Second item
Third item
JSX
import { Stack } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Stack gap="md">
      <div className="p-xs">First item</div>
      <div className="p-xs ms-auto">Second item</div>
      <div className="p-xs">Third item</div>
    </Stack>
  )
}

Responsive direction

direction takes an object in place of a value to switch the direction at one or more breakpoints: base is the direction from the narrowest width ('horizontal' when omitted), and a key named after a breakpoint (sm/md/lg/xl/2xl) is the direction from that breakpoint up, as in direction={{ base: 'vertical', md: 'horizontal' }}. The breakpoints are container queries rather than viewport media queries. gap takes the same object, gap={{ base: 'sm', md: 'lg' }}, but its gap-* classes in @chassis-ui/css follow the viewport, so a direction and a gap on one Stack can switch at different widths.

Responsive direction switching requires a .contains-inline ancestor to establish the container query context — <Stack> doesn't apply this itself, since the containment has to live on a parent of the element whose own layout is switching. Resize the browser to preview the transition between column and row layouts below:

JSX
import { Stack } from '@chassis-ui/react'

export const Example = () => {
  return (
    <div className="contains-inline">
      <Stack direction={{ base: 'vertical', sm: 'horizontal' }} gap={{ base: 'sm', sm: 'md' }}>
        <button type="button" className="button primary">
          Primary action
        </button>
        <button type="button" className="button primary outline">
          Cancel
        </button>
      </Stack>
    </div>
  )
}

API

Stack

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
direction?Responsive<"horizontal" | "vertical">—
Lays children out in a row (horizontal, the default, maps to .hstack) or a column (vertical, maps to .vstack). An object switches the direction from a breakpoint up: { base: 'vertical', md: 'horizontal' }. The breakpoints are container queries, so they require a .contains-inline ancestor (not applied by Stack itself — see the docs) to establish the container context they evaluate against.
gap?{ Responsive<Spacing | 0> }—
Spacing between children, mapped to the gap-* utility classes. Takes an object per breakpoint, as direction does: { base: 'sm', md: 'lg' }.
ref?any—