Skip to content

Grid ​

WxRow and WxCol are the 24-column grid a screen is laid out on: a form in two columns, a row of statistic cards, a filter bar that becomes a stack on a phone.

For the shell around the screen, see Layout; for a single row or stack of controls, Space is less machinery.

24 columns, split four ways
12
12
8
8
8
6
6
6
6
4
4
4
4
4
4
Offsets
8
8, offset 8
Responsive — drag the bottom-right corner and watch the row, not the window
Card 1
Card 2
Card 3
Card 4
The same markup in a 300px column
Card 1
Card 2
Card 3
Card 4

Usage ​

vue
<template>
  <wx-row :gutter="16">
    <wx-col :span="12">Left half</wx-col>
    <wx-col :span="12">Right half</wx-col>
  </wx-row>
</template>

span counts columns out of 24, so twelve is a half, eight a third, six a quarter.

Gutters ​

gutter is the gap between columns, in pixels or as any CSS length. Left alone it is --wx-gap, the step the surrounding layout spaces everything else by — 16 where nothing sets one. Once the columns wrap, the gap between lines is the same — unless gutter-y says otherwise:

vue
<template>
  <wx-row :gutter="24" :gutter-y="12">…</wx-row>
</template>

The gutter is half a gutter of padding on each column, pulled back by a negative margin on the row, rather than a column-gap. That is what keeps span="12" an honest half: a gap subtracted from the track would leave two halves wider than the line they sit on.

Responsive ​

span is the base and holds at every width. sm, md, lg and xl override it from 640, 768, 1024 and 1280px up — narrowest first, so a column that takes the whole line when there is little room and a quarter of it when there is plenty reads in that order:

vue
<template>
  <wx-col :span="24" :md="12" :lg="6">…</wx-col>
</template>

Each breakpoint also takes an offset of its own:

vue
<template>
  <wx-col :span="24" :lg="{ span: 16, offset: 4 }">…</wx-col>
</template>

The breakpoints measure the row, not the window ​

They are container queries: md means "from 768px of row", not "from 768px of viewport". The same grid therefore stacks inside a 400px drawer and spreads across a wide screen without knowing which it is in, and a main column that just lost 240px to a sidebar reflows the moment it narrows rather than when the window does. On a page whose content runs the full width the two readings agree, which is why the numbers are the familiar ones.

The container is named, so a WxCol used outside a WxRow does not start answering to the nearest card: with no row above it, a column keeps its base span at every width.

Support is Chrome 105, Safari 16 and Firefox 110 and up — anything older shows the base span, which for the usual mobile-first span="24" is a stack, not a broken layout.

Arranging the row ​

vue
<template>
  <wx-row justify="between" align="center" :wrap="false">…</wx-row>
</template>

order moves a column without moving it in the markup — the summary panel that belongs first on a phone and last on a desktop:

vue
<template>
  <wx-row>
    <wx-col :span="24" :lg="16" :order="2">The form</wx-col>
    <wx-col :span="24" :lg="8" :order="1">The summary</wx-col>
  </wx-row>
</template>

Row ​

PropTypeDefaultDescription
gutternumber | stringstepGap between columns
gutterYnumber | stringgutterGap between wrapped lines
justify'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'—Distribution along the row
align'start' | 'center' | 'end' | 'stretch' | 'baseline'—Alignment across it
wrapbooleantrueLets columns wrap
asstring | Component'div'The element to render

Col ​

PropTypeDefaultDescription
spannumber24Columns out of 24, at every width
offsetnumber—Empty columns before the cell
smnumber | { span?: number; offset?: number }—From 640px of row up
mdnumber | { span?: number; offset?: number }—From 768px of row up
lgnumber | { span?: number; offset?: number }—From 1024px of row up
xlnumber | { span?: number; offset?: number }—From 1280px of row up
ordernumber—Visual order within the row
asstring | Component'div'The element to render

Both take a default slot and nothing else.

How the breakpoints work ​

Every width a column is given is written out as a CSS variable — --wx-col-span, --wx-col-span-md and so on — and the stylesheet holds one @container rule per breakpoint, each falling back to the one below it. Nothing is generated per span, so the grid costs four rules rather than the several hundred a class-per-span grid ships, and a column can be adjusted from the outside:

vue
<template>
  <wx-col style="--wx-col-span: 10">Ten columns, set by hand</wx-col>
</template>

Released under the MIT License.