Stack
Flex layout primitives with typed responsive gap and direction, alignment, and optional asChild composition.
<VStack className="w-full max-w-md"> <DecorativeBox className="h-10" /> <DecorativeBox className="h-10" /> <DecorativeBox className="h-10" /></VStack>Usage
import { HStack, Stack, VStack } from "@reva/ui";Stack is a thin wrapper around Flex that adds opinionated defaults: gap-2, vertical direction, and smart cross-axis alignment (stretch when vertical, start when horizontal). HStack and VStack set direction for you.
For un-opinionated flex, responsive direction objects ({ default: "column", md: "row" }), or CSS-native direction names ("row" / "column"), use Flex directly.
Examples
Horizontal
Use the direction prop to change the direction of the stack.
<Stack direction="horizontal" justify="center"> <DecorativeBox className="size-10" /> <DecorativeBox className="size-10" /> <DecorativeBox className="size-10" /> <DecorativeBox className="size-10" /></Stack>HStack
Alternatively, you can use the HStack to create a horizontal stack and align its children horizontally.
<HStack align="center" justify="center"> <DecorativeBox className="h-12 w-24" /> <DecorativeBox className="size-8" /> <DecorativeBox className="size-8" /> <DecorativeBox className="h-8 w-24" /> <DecorativeBox className="size-8" /></HStack>VStack
Use the VStack to create a vertical stack and align its children vertically.
<VStack align="center"><DecorativeBox className="h-12 w-40" /><DecorativeBox className="size-12" /><DecorativeBox className="h-12 w-64" /></VStack>Responsive Direction
Pass a responsive object to change direction at different breakpoints.
<Stack direction={{ default: "vertical", md: "horizontal" }} gap={4} className="w-full"> <DecorativeBox className="h-20 flex-1" /> <DecorativeBox className="h-20 flex-1" /> <DecorativeBox className="h-20 flex-1" /></Stack>Gap
gap maps to Tailwind spacing steps (0–96 per the supported map). The default is 2 (gap-2). You can also pass a responsive object. Compare default spacing with gap={4}.
Default (gap-2)
gap={4}
<HStack gap={8} className="w-full" justify="center" wrap> <VStack> <p className="text-fg-muted text-2xs font-mono">Default (gap-2)</p> <Stack direction="horizontal" className="rounded-md border border-border-default p-2"> <DecorativeBox className="size-12" /> <DecorativeBox className="size-12" /> <DecorativeBox className="size-12" /> </Stack> </VStack> <VStack> <p className="text-fg-muted text-2xs font-mono">gap={4}</p> <Stack direction="horizontal" gap={4} className="rounded-md border border-border-default p-2"> <DecorativeBox className="size-12" /> <DecorativeBox className="size-12" /> <DecorativeBox className="size-12" /> </Stack> </VStack></HStack>Responsive gap
gap accepts the same responsive object shape as direction (breakpoints: default, sm, md, lg, xl, 2xl, 3xl).
<VStack gap={{ default: 2, md: 4, lg: 6 }} className="w-full max-w-md"> <DecorativeBox className="h-10" /> <DecorativeBox className="h-10" /> <DecorativeBox className="h-10" /></VStack>Align and justify
Use align for items-* and justify for justify-*.
<HStack justify="between" align="center" className="h-24 w-full max-w-md rounded-md border border-border-default px-3"> <DecorativeBox>Left</DecorativeBox> <DecorativeBox>Right</DecorativeBox></HStack>Child self-alignment
Default VStack alignment is stretch. Override a single child with self-center (or other self-* utilities).
<VStack gap={4} className="w-full max-w-md rounded-md border border-border-default p-3"> <DecorativeBox>Full width</DecorativeBox> <DecorativeBox className="self-center">Centered</DecorativeBox> <DecorativeBox>Full width</DecorativeBox></VStack>asChild
With asChild, layout props merge onto the child element (via Radix Slot). Use a semantic list while keeping flex row layout.
- Alpha
- Beta
- Gamma
<HStack asChild gap={4} className="rounded-md border border-border-default p-4"> <ul className="m-0 list-none p-0"> <li><DecorativeBox>Alpha</DecorativeBox></li> <li><DecorativeBox>Beta</DecorativeBox></li> <li><DecorativeBox>Gamma</DecorativeBox></li> </ul></HStack>Accessibility
Stack, HStack, and VStack are non-interactive layout wrappers. By default they render a div. Use asChild to attach layout to a semantic element (for example ul / nav) when structure matters for assistive technology. They do not set role or aria-* attributes—handle those on children when needed.
Props
Stack
Extends React.ComponentPropsWithoutRef<"div"> with the props below.
| Prop | Type | Default | Description |
|---|---|---|---|
direction | "horizontal" | "vertical" or responsive object | "vertical" | Main axis. Responsive: { default: "vertical", md: "horizontal" }. |
gap | Spacing step (0–96 per the supported map) or responsive object | 2 | gap-*. Responsive: { default: 2, md: 4, xl: 6 }. |
align | "start" | "end" | "center" | "stretch" | "baseline" | See description | Maps to items-*. If omitted: vertical stacks use stretch, horizontal stacks use start. |
justify | "start" | "end" | "center" | "between" | "around" | "evenly" | — | Maps to justify-*. |
wrap | boolean | "wrap" | "nowrap" | "wrap-reverse" | — | Flex wrap behaviour. |
asChild | boolean | false | Merge props onto the single child via Slot. |
HStack and VStack
Same props as Stack except direction: HStack fixes direction to "horizontal", VStack to "vertical". Use HStackProps and VStackProps from @reva/ui (Omit<StackProps, "direction">).