Stack
Opinionated vertical (or horizontal) flex container with token-driven gap. The reach-for primitive for stacking content. For row layouts with wrap or custom alignment, use Flex.
Dependencies
Source Code
import type { VariantProps } from 'cva';
import { Slot } from '@/components/slot';
import { cn, cva } from '@/lib/utils/classnames';
const stackStyle = cva({
base: 'flex',
variants: {
direction: {
column: 'flex-col',
row: 'flex-row',
'column-reverse': 'flex-col-reverse',
'row-reverse': 'flex-row-reverse',
},
align: {
start: 'items-start',
center: 'items-center',
end: 'items-end',
stretch: 'items-stretch',
baseline: 'items-baseline',
},
justify: {
start: 'justify-start',
center: 'justify-center',
end: 'justify-end',
between: 'justify-between',
around: 'justify-around',
evenly: 'justify-evenly',
},
gap: {
none: 'gap-0',
xs: 'gap-1',
sm: 'gap-2',
md: 'gap-4',
lg: 'gap-6',
xl: 'gap-8',
'2xl': 'gap-12',
},
wrap: {
true: 'flex-wrap',
false: 'flex-nowrap',
},
},
defaultVariants: {
direction: 'column',
align: 'stretch',
justify: 'start',
gap: 'md',
wrap: false,
},
});
interface StackProps
extends React.ComponentPropsWithRef<'div'>,
VariantProps<typeof stackStyle> {
asChild?: boolean;
}
const Stack = ({
ref,
className,
direction,
align,
justify,
gap,
wrap,
asChild,
...rest
}: StackProps) => {
const Comp = asChild ? Slot : 'div';
return (
<Comp
ref={ref}
className={cn(
stackStyle({ direction, align, justify, gap, wrap }),
className
)}
{...rest}
/>
);
};
export type { StackProps };
export { Stack }; API
| Prop | Default | Type | Description |
|---|---|---|---|
direction | - | 'column' | 'row' | 'column-reverse' | 'row-reverse' | Flex direction. Defaults to 'column' (the opinionated 'stack' shape). |
align | - | 'start' | 'center' | 'end' | 'stretch' | 'baseline' | Cross-axis alignment (align-items). |
justify | - | 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly' | Main-axis alignment (justify-content). |
gap | - | 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | Space between children using the standard bucket scale. |
wrap | - | boolean | Whether items wrap onto multiple lines. |
asChild | - | boolean | Render as the child element via Slot. |
Relation to Flex
Stack and Flex are siblings. Stack defaults to direction='column'; Flex defaults to 'row'. Both compile to identical Tailwind output for the same prop values. Use Stack for vertical-first composition, Flex for row-first or when you need Flex’s VStack/HStack aliases.
Examples
Vertical stack (default)
A bare <Stack> is a column with gap='md' between children.
Horizontal stack
Pass direction='row' for left-to-right composition. Equivalent to Flex without direction.
Gap scale
The gap prop accepts the standard bucket names. gap='none' removes spacing entirely.
Previous
Split
Next
Stat