Stack
One-dimensional layout primitive for vertical or horizontal flows with consistent spacing.
Overview
Stack is a one-dimensional layout primitive for arranging children in a vertical column or horizontal row with consistent gap spacing. It replaces ad-hoc space-y-* and flex gap-* boilerplate with a single declarative tag that controls direction, spacing, alignment, justification, and wrapping.
Why this exists
The most common layout task in any UI is placing items one after another — form fields down a page, buttons across a toolbar, content inside a card. Writing class="flex flex-col gap-4" or class="flex items-center gap-3" hundreds of times is repetitive and easy to get wrong. Stack wraps that pattern into a <div> with explicit props — every developer on the team uses the same direction, the same gap scale, and the same alignment API.
Mental model
Think of Stack as a flex container with a preset direction. Items flow one after the other — top to bottom when vertical, left to right when horizontal — separated by a uniform gap. You control the spacing between items, how items align across the cross axis, and how they distribute along the main axis.
When to use
- Vertical form spacing — label + input + helper text stacked down a form column
- Card content rhythm — title, description, metadata, and actions inside a card surface
- Settings sections — section heading followed by a group of related fields or options
- Dashboard filter rows — horizontal row of filter controls above a data table
- Page header actions — breadcrumb, title, and action buttons stacked vertically in a page header
- Toolbar layouts — icon buttons and controls arranged in a horizontal bar
- Ecommerce product form groups — price, stock, category fields in a vertical group with section label
- ERP / POS action rows — horizontal row of save, cancel, delete, and print buttons
- Starter-kit layouts — Laravel, React, and Vue pages built on Container + Section + Stack + Card
When not to use
- Do not use Stack for two-dimensional layouts — use Grid when items must align in rows and columns simultaneously
- Do not use Stack when content needs semantic grouping — use
<form>,<fieldset>,<nav>,<ul>/<li>, or<section>for meaning and wrap them in Stack for spacing - Do not use horizontal Stack without
wrapwhen children may overflow the container width on small screens - Do not use very large gaps (
gap={10}orgap={12}) in compact admin or form UIs — reserve those for page-level section spacing
Basic example
A vertical stack of form fields with standard spacing:
user@example.com
Password
********
Confirm password
********
<div class="flex flex-col gap-4">
<div class="rounded-lg border border-border bg-background p-4">
<p class="text-sm font-medium text-foreground">Email</p>
<p class="text-sm text-muted-foreground mt-1">user@example.com</p>
</div>
<div class="rounded-lg border border-border bg-background p-4">
<p class="text-sm font-medium text-foreground">Password</p>
</div>
<div class="rounded-lg border border-border bg-background p-4">
<p class="text-sm font-medium text-foreground">Confirm password</p>
</div>
</div>
Direction, gap, and alignment
Stack is controlled by three groups of props — direction, spacing, and alignment. Together they cover virtually every one-dimensional layout need.
Direction
| Value | Output class | Use case |
|---|---|---|
| vertical | flex flex-col | Form fields, card content, settings sections, stacked page layouts |
| horizontal | flex flex-row | Action rows, toolbars, filter bars, button groups, page header actions |
Gap scale
The gap prop maps to Tailwind's gap-* scale and applies consistent spacing between every child on both axes.
| Gap | Tailwind | Recommended use |
|---|---|---|
| 1 | gap-1 | Tight icon + label pairs, inline badges |
| 2 | gap-2 | Compact toolbars, dense action rows |
| 3 | gap-3 | Card content, small form groups |
| 4 | gap-4 | Standard form fields, dashboard filter rows, page sections |
| 5 | gap-5 | Settings sections, grouped content areas |
| 6 | gap-6 | Section-level spacing, card stacks |
| 8 | gap-8 | Page-level vertical breathing room |
| 10 | gap-10 | Spacious landing sections, large form separation |
| 12 | gap-12 | Major page section dividers |
Alignment
Control how items align on the cross axis (align) and distribute on the main axis (justify).
| Prop | Values | CSS output |
|---|---|---|
| align | start, center, end, stretch |
items-* |
| justify | start, center, end, between, around |
justify-* |
Use align="center" to vertically centre items in a horizontal stack. Use justify="between" to push items to opposite ends of a horizontal row (e.g., a label on the left and an action on the right).
Wrapping behavior
When direction="horizontal" and the children exceed the container width, set wrap to let items flow onto the next line. This is essential for responsive filter toolbars, tag lists, and badge groups on narrow viewports.
<Stack direction="horizontal" gap={2} wrap>
<FilterChip>Status</FilterChip>
<FilterChip>Category</FilterChip>
<FilterChip>Date range</FilterChip>
<FilterChip>Priority</FilterChip>
</Stack>
Anatomy
- Stack container —
<div class="flex flex-col gap-*">(vertical) or<div class="flex flex-row gap-*">(horizontal) - Children — direct child elements that flow sequentially in the chosen direction, separated by the gap value
- Gap — uniform spacing applied between all children via
gap-* - Alignment / justification — optional
items-*andjustify-*utilities applied to the container
Usage guidelines
- Use Stack for every one-dimensional spacing need — it keeps gap values consistent across the whole codebase.
- Prefer
verticalfor forms, card content, settings, and page sections. - Prefer
horizontalfor toolbars, action rows, filter bars, and page header actions. - Use semantic HTML elements as children (
<form>,<nav>,<section>,<ul>) when the content needs meaning — Stack is a visual wrapper. - Wrap Stack + Card in Section for page-level vertical rhythm, then wrap everything in Container for max-width.
- Use consistent gap values across repeated screens — all card content stacks should use the same
gapvalue. - Enable
wrapon horizontal stacks that contain dynamic or responsive content to avoid overflow.
Do and Don't
Do
- Use Stack for one-dimensional spacing
- Use vertical direction for forms and content sections
- Use horizontal direction for toolbars, filter rows, and actions
- Use
wrapfor responsive horizontal groups - Use consistent gap values across similar page patterns
- Use
alignandjustifyfor precise layout control
Don't
- Use Stack for two-dimensional layouts — use Grid
- Hardcode
space-y-*orgap-*when the Stack gap prop exists - Rely on visual order that differs from DOM order
- Use horizontal Stack without
wrapwhen content may overflow - Use very large gaps in compact admin or form UIs
- Add margin or padding to children — let the Stack gap handle spacing
Accessibility
Stack is a visual layout primitive — it renders a plain <div> with no ARIA roles or attributes. It does not interfere with assistive technology.
- Use semantic elements as children. Wrap Stack content inside
<form>,<fieldset>,<nav>,<ul>/<li>,<section>,<header>, or<aside>when the grouped content has meaning. Stack provides the spacing; semantics provide the meaning. - Keep DOM order logical. Screen readers and keyboard focus follow DOM order, not visual order. Do not reorder children visually in a way that changes the reading or tab sequence.
- Do not add ARIA roles. Stack is not an interactive widget. Applying
role="list",role="toolbar", or similar roles to a plain spacing div is incorrect — add those roles to the semantic parent, not the Stack container.
Customization
Stack outputs Tailwind flex utility classes. Override direction, spacing, or alignment by passing additional Tailwind classes via className (React) or class (Vue / HTML). The component uses cn() to merge classes — your custom utilities take precedence.
For advanced layouts, combine Stack with Grid inside page sections. For example, use Stack to arrange a vertical settings page where each section contains a Grid of fields: Container → Section → Stack → Grid.
HTML example
A vertical card content stack with title, description, metadata, and action row:
<div class="rounded-xl border border-border bg-card p-6 shadow-sm">
<div class="flex flex-col gap-3">
<h3 class="text-lg font-semibold text-foreground">Project Settings</h3>
<p class="text-sm text-muted-foreground">Configure deployment, environment, and team access.</p>
<div class="flex flex-row items-center gap-2 text-sm text-muted-foreground">
<span class="rounded-md bg-muted px-2 py-0.5">Updated 2h ago</span>
<span class="rounded-md bg-muted px-2 py-0.5">v2.4.1</span>
</div>
<div class="flex flex-row gap-2 pt-2">
<button class="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground">Save</button>
<button class="rounded-md border border-border bg-background px-4 py-2 text-sm font-medium text-foreground">Cancel</button>
</div>
</div>
</div>
React example
import { Stack } from '@byteion/react';
function SettingsCard() {
return (
<div className="rounded-xl border border-border bg-card p-6 shadow-sm">
<Stack gap={3}>
<h3 className="text-lg font-semibold text-foreground">Project Settings</h3>
<p className="text-sm text-muted-foreground">
Configure deployment, environment, and team access.
</p>
<Stack direction="horizontal" gap={2} align="center">
<span className="rounded-md bg-muted px-2 py-0.5 text-sm text-muted-foreground">
Updated 2h ago
</span>
<span className="rounded-md bg-muted px-2 py-0.5 text-sm text-muted-foreground">
v2.4.1
</span>
</Stack>
<Stack direction="horizontal" gap={2} className="pt-2">
<Button>Save</Button>
<Button variant="outline">Cancel</Button>
</Stack>
</Stack>
</div>
);
}
function FilterToolbar() {
return (
<Stack direction="horizontal" gap={2} wrap align="center">
<Select placeholder="Status" />
<Select placeholder="Category" />
<Input placeholder="Search…" className="w-48" />
<Button variant="ghost" size="sm">Reset</Button>
</Stack>
);
}
Vue example
<script setup lang="ts">
import { Stack } from '@byteion/vue';
import { Button } from '@byteion/vue';
</script>
<template>
<div class="rounded-xl border border-border bg-card p-6 shadow-sm">
<Stack :gap="3">
<h3 class="text-lg font-semibold text-foreground">Project Settings</h3>
<p class="text-sm text-muted-foreground">
Configure deployment, environment, and team access.
</p>
<Stack direction="horizontal" :gap="2" align="center">
<span class="rounded-md bg-muted px-2 py-0.5 text-sm text-muted-foreground">
Updated 2h ago
</span>
<span class="rounded-md bg-muted px-2 py-0.5 text-sm text-muted-foreground">
v2.4.1
</span>
</Stack>
<Stack direction="horizontal" :gap="2" class="pt-2">
<Button>Save</Button>
<Button variant="outline">Cancel</Button>
</Stack>
</Stack>
</div>
</template>
API Reference
React
<Stack> extends HTMLAttributes<HTMLDivElement> — all standard div attributes pass through.
| Prop | Type | Default |
|---|---|---|
| direction | 'vertical' | 'horizontal' |
'vertical' |
| gap | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 |
4 |
| align | 'start' | 'center' | 'end' | 'stretch' |
— |
| justify | 'start' | 'center' | 'end' | 'between' | 'around' |
— |
| wrap | boolean |
false |
Vue
<Stack> accepts the same props as the React version. All standard HTML attributes pass through.
| Prop | Type | Default |
|---|---|---|
| direction | 'vertical' | 'horizontal' |
'vertical' |
| gap | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 |
4 |
| align | 'start' | 'center' | 'end' | 'stretch' |
— |
| justify | 'start' | 'center' | 'end' | 'between' | 'around' |
— |
| wrap | boolean |
false |
Developer tips
- Stack is the default layout. If you are unsure which primitive to use, start with Stack and switch to Grid only when you need two-dimensional control.
- Use
justify="between"for split layouts. In a horizontal Stack,justify="between"pushes the last item to the far end — useful for "label + action" rows and page header title + button layouts. - Use
align="center"in horizontal stacks. By default, items in a horizontal stack stretch to fill the height. Addalign="center"to vertically centre them. - Combine with Container + Section. This trio creates a well-structured page: Container (width) → Section (padding) → Stack (spacing) → Card (surface).
- Use absolute gap values. Stick to the supported scale (
1–12) instead of customspace-y-*or arbitrary margin values. - Nested stacks are fine. Unlike Grid, nesting Stack inside Stack is common and expected — a horizontal action row inside a vertical card content stack is a standard pattern.
Common mistakes
- Using Stack for grid layouts — Stack is one-dimensional. When you need items to align in rows and columns simultaneously, use Grid.
- Mixing inconsistent gap values — using
gap={3}on one card,gap={4}on another, andgap={5}on a third creates uneven visual rhythm. Define a gap scale per page or section type. - Creating inaccessible visual order — CSS order and
flex-direction: row-reverseorflex-direction: column-reversechange visual order but not DOM order. Screen readers and keyboard focus follow the DOM, creating a confusing experience. - Forgetting
wrapon horizontal responsive rows — withoutwrap, a horizontal Stack with many children overflows the viewport on mobile, causing horizontal scroll. - Using Stack to replace semantic grouping elements — do not wrap a group of links in Stack with no
<nav>, or a group of form fields with no<fieldset>. Stack provides spacing; semantic elements provide meaning. - Adding margins to children — the
gapprop handles spacing between children. Adding individual margins to children breaks the layout contract and makes spacing unpredictable.
Production usage tips
- Keep spacing consistent across repeated product screens — all form pages should use the same gap value; all card content stacks should share a gap value. This creates a predictable visual rhythm.
- Test horizontal stacks at mobile widths — enable
wrapfor filter toolbars, tag groups, and action rows. Verify items wrap without overlapping or overflowing. - Keep DOM order logical — screen reader and keyboard tab order follows the DOM. Do not rely on
flex-direction: row-reverseor CSSorder-*to reorder interactive content. - Use Grid for two-dimensional layout and Stack for one-dimensional flow — they are complementary. A typical page uses both: Grid for the card layout, Stack inside each card for content rhythm.
- Align React / Vue props with core HTML examples — the canonical HTML rendering is the source of truth. Ensure all three frameworks produce the same visual output for the same prop values.
- Validate dark mode and branded themes — Stack itself uses no colour tokens, but its children do. Test inside Card, Button, and other primitives under all themes.
- For Laravel / server-rendered apps — use the raw HTML structure shown in the HTML example. Stack is a zero-JS component — the
data-bi-component="layout-stack"attribute is for documentation and debugging only. - For React / Vue SPAs — import from
@byteion/reactor@byteion/vue. Pair Stack with Container, Section, and Grid for full page hierarchy.
Premium examples
Pro patterns available in Byteion Pro:
- Settings page section stack — grouped setting sections using Stack for vertical rhythm, each section containing a Card with form fields, toggle switches, and save actions
- Dashboard filter toolbar — horizontal Stack with wrapped Select, Input, DatePicker, and Button children, aligned to centre with consistent
gap={2} - Ecommerce product editor form stack — vertical Stack of form sections (pricing, inventory, shipping) with section headers, fields, and inline validation
- POS action row — horizontal Stack of large action buttons (Charge, Refund, Hold, Print Receipt) with
justify="between"andgap={4} - ERP record detail layout — vertical Stack of detail sections (order info, line items, shipping, payment history) each wrapped in a Card, with horizontal action rows inside each card
- Admin page header action stack — vertical Stack with breadcrumb, page title + description, and a horizontal Stack of action buttons (Create, Export, Filter) with
justify="between"
Related components
- Container — page-level width and horizontal padding
- Grid — two-dimensional layout for rows and columns
- Section — vertical spacing between page areas
- Card — surface for grouping related content, paired with Stack for interior rhythm
API Reference
Related components
Pair this component with adjacent Byteion primitives from the same workflow: form controls for data entry, feedback components for validation, and layout primitives for spacing.
Runtime events
Byteion keeps framework APIs idiomatic: HTML uses DOM custom events, React uses callback props, and Vue uses emitted events / v-model updates.
HTML / JS events
No HTML runtime events are declared by this adapter.
React callbacks
No React callback events are declared by this adapter.
Vue emits
No Vue emitted events are declared by this adapter.
Remote / AJAX
This component does not implement Byteion JS remote loading. Use normal HTML form submission, framework state, or your application data layer around it.
Unlock Premium Patterns
Get access to copy-paste ready Pro blocks, SaaS templates, and advanced component patterns.
Explore Pro Components