Layout Components
When to Use
Use when building reusable spacing, flex, and grid primitives. Layout components standardize spacing and remove repetitive Tailwind class sets from feature code.
Decision
| If you need... | Use... | Why |
|---|---|---|
| Vertical or horizontal list with gap | Stack component |
Abstracts flex flex-col gap-{n} or flex flex-row gap-{n} |
| Flex container with alignment control | Flex component |
Wraps display: flex with props for align, justify, wrap |
| CSS grid layout | Grid component |
Wraps display: grid with cols, gap props |
| Responsive max-width wrapper | Container component |
Consistent page width constraints from design tokens |
| Responsive prop (different value per breakpoint) | Responsive prop object { base: 2, md: 4 } or array |
Maps to Tailwind responsive prefixes |
Pattern
Stack (most common layout primitive):
type StackProps = {
direction?: 'row' | 'col';
gap?: 1 | 2 | 3 | 4 | 6 | 8 | 10 | 12; // constrain to spacing scale
align?: 'start' | 'center' | 'end' | 'stretch';
children: React.ReactNode;
className?: string;
};
const gapMap = { 1: 'gap-1', 2: 'gap-2', 3: 'gap-3', 4: 'gap-4', 6: 'gap-6', 8: 'gap-8', 10: 'gap-10', 12: 'gap-12' } as const;
const alignMap = { start: 'items-start', center: 'items-center', end: 'items-end', stretch: 'items-stretch' } as const;
export function Stack({ direction = 'col', gap = 4, align = 'stretch', children, className }: StackProps) {
return (
<div className={cn('flex', direction === 'col' ? 'flex-col' : 'flex-row', gapMap[gap], alignMap[align], className)}>
{children}
</div>
);
}
// Usage: <Stack direction="row" gap={3} align="center"><Icon /><Text>Label</Text></Stack>
Container:
export function Container({ children, className }: { children: React.ReactNode; className?: string }) {
return <div className={cn('mx-auto w-full max-w-screen-xl px-4 sm:px-6 lg:px-8', className)}>{children}</div>;
}
Common Mistakes
- Wrong: Accepting arbitrary number for
gapwithout constraining to spacing scale → Right: Constrain to valid spacing values; unlimited gap breaks design system consistency - Wrong: Using
marginfor spacing between layout items → Right: Usegapon flex/grid containers; margin breaks at edges and doesn't compose - Wrong: Building layout components with CSS-in-JS or style props → Right: Tailwind classes are tree-shaken and static; style props bypass optimization
- Wrong: Duplicating layout logic in every feature component → Right: Extract Stack/Flex/Grid once; 20 components with
flex flex-col gap-4is a Stack - Wrong: Making layout components too flexible with unlimited responsive prop combinations → Right: Constrain to the spacing scale; untested class combinations create visual bugs