Most application layouts do not require custom CSS.
They require a small set of predictable decisions:
Vuesion expresses these decisions through dedicated layout components.
Instead of repeatedly implementing layouts with custom classes and media queries, developers compose interfaces from a small set of reusable primitives.
Traditional layout code often describes implementation details:
.form {
display: flex;
flex-direction: column;
gap: 16px;
}
With Vuesion, the template describes the intended layout directly:
<vue-stack space="16">
<vue-input />
<vue-input />
<vue-button>Submit</vue-button>
</vue-stack>
The component name communicates the structure without requiring the reader to inspect a stylesheet.
Layout becomes declarative rather than imperative.
The layout components follow the same mental model as Auto Layout in Figma.
A designer may describe a section as:
Vertical Auto Layout
24px spacing
Centered horizontally
Responsive padding
The implementation uses the same concepts:
<vue-stack space="24" align-x="center" padding="16 24">
...
</vue-stack>
This creates a shared vocabulary between design and development and reduces the amount of interpretation required when implementing an interface.
The layout components are built on the same design tokens that power the Vuesion Design System.
Spacing values, breakpoints, widths, alignment options, and other layout-related properties are strongly typed and shared with the Figma library.
For example:
<vue-stack space="24">
The space property only accepts values that exist in the design system.
Arbitrary spacing values such as 17px or 23px cannot accidentally be introduced.
This provides several advantages:
Rather than treating spacing as free-form CSS, Vuesion treats it as part of the shared language between design and development.
VueBox is the smallest layout primitive in Vuesion.
Every other layout component builds on top of it.
VueBox
├── VueStack
├── VueInline
├── VueColumns
├── VueColumn
└── VueContentBlock
It provides the common behavior required by all layouts:
VueBox does not prescribe a particular layout direction. It provides the foundation from which more specialized components are composed.
Use it when you need a lightweight wrapper with responsive spacing or alignment but no dedicated Stack, Inline, or Columns behavior.
<vue-box as="section" padding="24">
...
</vue-box>
VueStack arranges children vertically.
It is the default choice for interfaces whose elements follow one another from top to bottom.
Typical examples include:
<vue-stack space="24">
<vue-text as="h2" look="h2">
Account settings
</vue-text>
<profile-form />
</vue-stack>
The Stack owns the spacing between its children.
Individual children should usually not add margins to position themselves inside the layout.
VueInline arranges children horizontally.
It is useful when elements belong together on the same visual row.
Typical examples include:
<vue-inline space="8" align-y="center">
<vue-icon name="user" />
<vue-text>Account</vue-text>
</vue-inline>
An Inline can wrap or change its behavior responsively when the available space becomes limited.
VueColumns creates horizontal layouts consisting of one or more columns.
It is intended for larger structural relationships such as:
<vue-columns space="24">
<vue-column :width="['full', '3/10']">
...
</vue-column>
<vue-column :width="['full', '6/10']">
...
</vue-column>
</vue-columns>
Columns describe how the available width is divided without requiring custom grid or flexbox rules for each page.
VueColumn represents an individual child inside VueColumns.
It controls properties such as:
A column can fill the remaining space or keep a fixed content width depending on the layout.
<vue-column no-grow>
...
</vue-column>
<vue-column>
...
</vue-column>
The relationship between VueColumns and VueColumn makes page-level layouts explicit and easy to understand from the template alone.
VueContentBlock controls the horizontal boundaries of page content.
Instead of defining a new maximum width and responsive side padding for every page, content blocks provide a consistent page container.
Typical use cases include:
<vue-content-block padding="48 24">
<vue-stack space="32">
...
</vue-stack>
</vue-content-block>
This keeps content widths and page padding consistent throughout the product.
Layout decisions often change across screen sizes.
Vuesion layout components accept responsive values directly through their props.
<vue-stack :space="['16', '24', '32']" :padding="['16', '24 32']">
...
</vue-stack>
Each value maps to the configured breakpoint order.
When fewer values are provided than breakpoints exist, the most recent value continues to apply until another value replaces it.
This makes responsive behavior visible in the template and reduces the need for isolated media queries.
Layout components are intended to be nested.
A complete page may combine several primitives:
<vue-content-block padding="48 24">
<vue-stack space="32">
<vue-inline align-x="between" align-y="center">
<vue-text as="h1" look="h1">
Workspace members
</vue-text>
<vue-button>Add member</vue-button>
</vue-inline>
<vue-columns space="24">
<vue-column :width="['full', '7/10']">
<workspace-member-list />
</vue-column>
<vue-column :width="['full', '3/10']">
<workspace-summary />
</vue-column>
</vue-columns>
</vue-stack>
</vue-content-block>
Each component solves one layout problem.
Together, they describe the complete interface without introducing page-specific layout CSS.
A central rule of the layout system is that parents control the position and spacing of their children.
Avoid giving individual children margins merely to place them inside a particular page.
Instead of:
<div class="form">
<vue-input class="input" />
<vue-button class="submit">Save</vue-button>
</div>
.form {
display: flex;
flex-direction: column;
}
.input {
margin-bottom: 16px;
}
Prefer:
<vue-stack space="16">
<vue-input />
<vue-button>Save</vue-button>
</vue-stack>
This makes components easier to reuse because they do not carry assumptions about the layout in which they appear.
Custom CSS is still appropriate for visual effects or layouts that cannot be expressed with the available primitives.
However, common structural decisions should generally use the layout system.
Prefer:
<vue-inline space="8" align-y="center">
...
</vue-inline>
over:
.actions {
display: flex;
align-items: center;
gap: 8px;
}
Prefer:
<vue-content-block>
...
</vue-content-block>
over repeatedly defining:
.page {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
The goal is not to eliminate CSS.
The goal is to avoid rewriting the same layout behavior throughout the application.
Use custom CSS when a layout has requirements that are genuinely specific to the feature.
Examples include:
Even then, layout primitives can often provide the outer structure while custom CSS handles only the exceptional part.
Layouts are one of the most frequently repeated parts of application development.
Without a shared system, every page introduces slightly different spacing, breakpoints, widths, and alignment rules.
Vuesion centralizes these decisions inside composable layout components.
This provides:
The result is a layout system that stays predictable as the product grows.
Continue with Storybook to learn how Vuesion develops, documents, and tests components in isolation before they are used inside complete pages and user flows.