// preview in
saved for every page

Stack

Lays its children out in one column or one row, with a gap from the spacing scale. Use it for forms, toolbars, lists and anything that flows in one direction.

Pattern CSS flexboxServer componentSource ↗
minimal · light · #3fa34d
direction
align
justify
wrap

Installation

Set up Camaleo once (Installation), then import it. It has no state, so it renders on the server.

import { Stack } from "@camaleo/react";

Anatomy

One flex element with data-slot="stack". Stacks nest: this page header is a row whose two children are stacks of their own.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d

We send invoices here.

gap={1} · Label and value: one idea

Invoice

#2026-118

Due

11/20/2026

gap={3} · Items in a list

gap={6} · Separate groups

Billing

#2026-118

Shipping

Belo Horizonte

Gap shows what belongs together

gap counts steps of --cml-space, so the rhythm follows the skin. Small gaps join a label to its value; large gaps separate groups.

Projects

12 active

Page header row

justify="space-between" puts the title on one side and the actions on the other. With wrap, the actions drop below the title on a phone.

Topics

  • Design systems
  • Accessibility
  • React
  • Performance
  • Typography
  • Dark mode

Tags that wrap

A row of tags should wrap, not scroll sideways or squeeze. It is also a ul, so screen readers say how many topics there are.

Lucas Andrade

Account manager · Atlas

Row or column

Switch it on. The same three children turn from a row into a column; only direction changes, so the reading order stays the same.

Tab order 1

Tab order 2

Tab order 3

Tab follows what you see: left to right.

Visual order equals Tab order

Turn on row-reverse and press Tab: focus starts on the right. To put the main action at the end, place it last in the DOM and use justify="flex-end".

Workspace

Members

8 of 10 seats

Storage

34 GB of 100 GB

Plan

Team, monthly

Rows with dividers

Stack has no divider prop. Put a Separator between children and the gap spaces it evenly above and below.

On call this week

  • Beatriz Santos

    Backend

  • João Pereira

    Infrastructure

  • Carla Mendes

    Frontend

A list that stacks

as="ul" keeps list semantics while Stack handles the spacing. Remove the bullets and the indent with listStyle and padding.

Responsive without breakpoints

There are no breakpoint props. Give each child a minimum width with flex and turn on wrap: three fields in a row become one column on a phone.

In context

These are whole pieces of UI you can copy, in the skin you picked.

Order summary

Subtotal

$412.00

Shipping

$18.90

Coupon WELCOME10

−$41.20

Total$389.70
Order summaryCard · Stack · Separator · Button
Helena DuartePro

Product designer · São Paulo

Profile headerCard · Stack · Avatar · Badge · Button

Create your workspace

Free for 14 days. No card needed.

Sign-up formCard · Stack · Field · Input · Checkbox

Guidelines

Invoice #2026-118

Due 11/20/2026 · $1,240.00

Payment by bank transfer or card.

DoTight gaps inside a group, wide gaps between groups.

The title and its due date read as one thing, and the action stands apart.

Invoice #2026-118

Due 11/20/2026 · $1,240.00

Payment by bank transfer or card.

Don’tThe same gap everywhere.

Every line is equally far from the next, so nothing says what belongs together.

DoOrder the DOM the way it reads.

Cancel comes first and Publish last, pushed to the end with justify="flex-end". Tab follows the eye.

Don’trow-reverse to move the main button.

It looks identical, but Tab now starts on the right and moves left, and screen readers read Publish before Cancel.

Props

PropTypeDefaultDescription
as"div" | "section" | "ul" | "form" | …"div"Element to render, for the right semantics (e.g. as="ul").
direction"column" | "column-reverse" | "row" | "row-reverse""column"Main axis. The -reverse values only flip the picture: reading and Tab order still follow the DOM.
gapnumber0Space between children, in multiples of --cml-space (0.25rem by default): gap={4} = 1rem.
alignCSS align-items"stretch"Cross-axis alignment (align-items).
justifyCSS justify-content"flex-start"Main-axis distribution (justify-content).
wrapbooleanfalseLets children wrap onto new lines when they don't fit.

as takes the same tags as Box. Every other prop goes to the element. Your style is merged after the custom properties, so it can override any of them.

Styling hooks

Each prop becomes a custom property on the element. Leave a prop out and your stylesheet can set its property instead, for example at a breakpoint.

Attributes

data-slot"stack"

Tokens it reads

This component only

--cml-space--cml-stack-align--cml-stack-direction--cml-stack-gap--cml-stack-justify--cml-stack-wrap
/* the actions bar becomes a row from 40rem up */
@media (min-width: 40rem) {
  .actions[data-slot="stack"] {
    --cml-stack-direction: row;
    --cml-stack-justify: flex-end;
  }
}

Accessibility

—Stack renders no interactive element. Tab moves through its children in DOM order.
Was this page helpful? · Edit this page on GitHub