Layout Components

Most application layouts do not require custom CSS.

They require a small set of predictable decisions:

  • Should elements be arranged vertically or horizontally?
  • How much space should exist between them?
  • How wide should the content become?
  • How should it behave across breakpoints?
  • How should children be aligned?

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.

Layout becomes declarative

Traditional layout code often describes implementation details:

SCSS
.form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

With Vuesion, the template describes the intended layout directly:

Vue
<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.

A shared language with Figma

The layout components follow the same mental model as Auto Layout in Figma.

A designer may describe a section as:

Text
Vertical Auto Layout
24px spacing
Centered horizontally
Responsive padding

The implementation uses the same concepts:

Vue
<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.

Typed design tokens

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
<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:

  • Designers and developers use the same spacing scale.
  • Autocomplete only suggests valid values.
  • Layouts remain visually consistent across the application.
  • Design decisions are encoded directly into the type system.

Rather than treating spacing as free-form CSS, Vuesion treats it as part of the shared language between design and development.

VueBox

VueBox is the smallest layout primitive in Vuesion.

Every other layout component builds on top of it.

Text
VueBox
├── VueStack
├── VueInline
├── VueColumns
├── VueColumn
└── VueContentBlock

It provides the common behavior required by all layouts:

  • A configurable semantic element
  • Responsive padding
  • Horizontal alignment
  • Vertical alignment
  • Different display modes
  • Responsive values across breakpoints

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
<vue-box as="section" padding="24">
  ...
</vue-box>

VueStack

VueStack arranges children vertically.

It is the default choice for interfaces whose elements follow one another from top to bottom.

Typical examples include:

  • Forms
  • Page sections
  • Cards
  • Dialog content
  • Settings panels
  • Lists of controls
Vue
<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

VueInline arranges children horizontally.

It is useful when elements belong together on the same visual row.

Typical examples include:

  • Button groups
  • Toolbars
  • Tags
  • Metadata
  • Compact controls
  • Icon and label combinations
Vue
<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

VueColumns creates horizontal layouts consisting of one or more columns.

It is intended for larger structural relationships such as:

  • Sidebar and content layouts
  • Form columns
  • Dashboard sections
  • Master-detail views
  • Responsive page structures
Vue
<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

VueColumn represents an individual child inside VueColumns.

It controls properties such as:

  • Responsive width
  • Growth behavior
  • Shrinking behavior
  • Internal padding
  • Alignment

A column can fill the remaining space or keep a fixed content width depending on the layout.

Vue
<vue-column no-grow>
  ...
</vue-column>
Vue
<vue-column>
  ...
</vue-column>

The relationship between VueColumns and VueColumn makes page-level layouts explicit and easy to understand from the template alone.

VueContentBlock

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:

  • Landing page sections
  • Documentation content
  • Application pages
  • Settings screens
  • Full-width page sections with constrained inner content
Vue
<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.

Responsive values

Layout decisions often change across screen sizes.

Vuesion layout components accept responsive values directly through their props.

Vue
<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.

Compose layouts from simple primitives

Layout components are intended to be nested.

A complete page may combine several primitives:

Vue
<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.

Spacing belongs to the parent

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:

Vue
<div class="form">
  <vue-input class="input" />
  <vue-button class="submit">Save</vue-button>
</div>
SCSS
.form {
  display: flex;
  flex-direction: column;
}

.input {
  margin-bottom: 16px;
}

Prefer:

Vue
<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.

Prefer layout components over page-specific CSS

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
<vue-inline space="8" align-y="center">
  ...
</vue-inline>

over:

SCSS
.actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

Prefer:

Vue
<vue-content-block>
  ...
</vue-content-block>

over repeatedly defining:

SCSS
.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.

When custom CSS is appropriate

Use custom CSS when a layout has requirements that are genuinely specific to the feature.

Examples include:

  • Complex overlapping elements
  • Decorative positioning
  • Visual effects
  • Animations
  • Highly specialized grid arrangements

Even then, layout primitives can often provide the outer structure while custom CSS handles only the exceptional part.

Why this approach?

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:

  • Consistent spacing
  • Responsive behavior without repetitive media queries
  • Templates that communicate layout intent
  • Shared concepts between Figma and code
  • Fewer page-specific CSS rules
  • Components that remain independent from their surroundings

The result is a layout system that stays predictable as the product grows.

Next steps

Continue with Storybook to learn how Vuesion develops, documents, and tests components in isolation before they are used inside complete pages and user flows.