Skip to content

NbGrid is a flexible layout primitive built on CSS flexbox. A dir="row" grid arranges children horizontally; a dir="col" grid arranges them vertically. Nest them freely to build any layout.

The grid is configured at compile time via src/styles/variables/_grid.scss.

Breakpoints ​

All breakpoints are mobile-first (min-width). Base styles apply at all viewport sizes. A rule defined at md kicks in from 672px upward and stays active unless a wider breakpoint overrides it.

NameMin-width
sm320px
md672px
lg1056px
xl1312px
xxl1584px

How responsive props work ​

Most layout props (dir, gap, grid, justify, align, wrap, visible) accept three input forms:

1. Scalar — applies at all viewport sizes:

vue
<nb-grid dir="col">...</nb-grid>

2. Breakpoint map — different values per breakpoint. Rules cascade upward; only the breakpoints you define are set:

vue
<!-- col until 672px, then row -->
<nb-grid :dir="{ sm: 'col', md: 'row' }">...</nb-grid>

3. Function — called reactively at render time. Any reactive state accessed inside is tracked automatically:

vue
<script setup lang="ts">
import { ref } from 'vue'
const isExpanded = ref(false)
</script>

<template>
  <nb-grid :dir="() => (isExpanded ? 'col' : 'row')">...</nb-grid>
</template>

TIP

The function form is for dynamic logic that does not map cleanly to breakpoints — for example, toggling layout based on component state. For viewport-driven changes, use the breakpoint map.

Props that accept responsive forms ​

PropScalarBreakpoint mapFunction
dir✓✓✓
gap✓✓✓
grid✓✓✓
shift✓✓✓
justify✓✓✓
align✓✓✓
wrap✓✓✓
visible✓✓✓
first✓array form-
last✓array form-
reverse✓array form-
grow✓--
flex✓--
shrink✓--

first, last, and reverse use an array of breakpoint names instead of an object: :first="['sm', 'md']".

Visual demo ​

Getting a ref ​

NbGrid exposes a getRef() method that returns the underlying DOM element.

vue
<template>
  <nb-grid ref="myGrid"> content </nb-grid>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const myGrid = ref()
console.log(myGrid.value.getRef()) // → HTMLElement
</script>

The grid prop sets how many of the 16 available columns a child item spans. The shift prop offsets it from the left edge.

Column spanning ​

vue
<template>
  <nb-grid dir="row">
    <nb-grid dir="col" grid="4">4 cols</nb-grid>
    <nb-grid dir="col" grid="12">12 cols</nb-grid>
  </nb-grid>
</template>

Responsive columns ​

Pass a breakpoint map to change column spans at different screen widths.

vue
<template>
  <nb-grid dir="row">
    <nb-grid dir="col" :grid="{ sm: 16, md: 8 }">Left</nb-grid>
    <nb-grid dir="col" :grid="{ sm: 16, md: 8 }">Right</nb-grid>
  </nb-grid>
</template>

Column shift (offset) ​

Use shift to push a column to the right by a number of column widths.

vue
<template>
  <nb-grid dir="col" grid="8" shift="4">centered-ish</nb-grid>
</template>

The dir prop controls the main axis: row lays children side by side; col stacks them top to bottom.

Basic direction ​

vue
<template>
  <!-- Horizontal -->
  <nb-grid dir="row">
    <nb-grid dir="col">First</nb-grid>
    <nb-grid dir="col">Second</nb-grid>
  </nb-grid>
  <!-- Vertical -->
  <nb-grid dir="col">
    <nb-grid dir="row">First</nb-grid>
    <nb-grid dir="row">Second</nb-grid>
  </nb-grid>
</template>

Responsive direction ​

vue
<template>
  <!-- col on small, row on medium+ -->
  <nb-grid :dir="{ sm: 'col', md: 'row' }">
    <nb-grid :dir="{ sm: 'row', md: 'col' }">First</nb-grid>
    <nb-grid :dir="{ sm: 'row', md: 'col' }">Second</nb-grid>
  </nb-grid>
</template>

The gap prop controls spacing between children using named size tokens.

Gap scale ​

TokenValue
xxs2px
xs4px
sm8px
md16px
lg24px
xl32px
xxl48px

Column gaps ​

Row gaps ​

vue
<template>
  <nb-grid dir="row" gap="md">
    <nb-grid dir="col">One</nb-grid>
    <nb-grid dir="col">Two</nb-grid>
  </nb-grid>
</template>

Responsive gaps ​

vue
<template>
  <nb-grid dir="row" :gap="{ sm: 'xs', md: 'xl' }">
    <nb-grid dir="col" grow>One</nb-grid>
    <nb-grid dir="col" grow>Two</nb-grid>
  </nb-grid>
</template>

Horizontal alignment (justify) ​

TIP

justify="evenly" sets equal spacing between items. distributed makes items grow equally to fill the available width. They solve different problems.

vue
<template>
  <nb-grid dir="row" justify="between">
    <nb-grid dir="col">Left</nb-grid>
    <nb-grid dir="col">Right</nb-grid>
  </nb-grid>
</template>

Vertical alignment (align) ​

vue
<template>
  <nb-grid dir="row" align="center" style="height: 120px">
    <nb-grid dir="col" grow>Vertically centered</nb-grid>
  </nb-grid>
</template>

The wrap prop controls what happens when children overflow the container's inline axis.

vue
<template>
  <NbGrid is="ul" wrap="wrap" gap="sm">
    <NbGrid is="li" dir="col">1</NbGrid>
    <NbGrid is="li" dir="col">2</NbGrid>
    <NbGrid is="li" dir="col">3</NbGrid>
  </NbGrid>
</template>

wrap also supports a breakpoint map:

vue
<NbGrid :wrap="{ sm: 'wrap', lg: 'nowrap' }">...</NbGrid>

Use first and last boolean props to reorder items visually without changing DOM order. Use reverse to flip the entire row or column.

First ​

vue
<template>
  <nb-grid dir="row">
    <nb-grid dir="col">DOM first</nb-grid>
    <nb-grid dir="col">DOM second</nb-grid>
    <nb-grid dir="col" first>DOM third — renders first</nb-grid>
  </nb-grid>
</template>

Last ​

Reverse ​

vue
<template>
  <nb-grid dir="row" reverse>
    <nb-grid dir="col">First</nb-grid>
    <nb-grid dir="col">Second</nb-grid>
    <nb-grid dir="col">Third</nb-grid>
  </nb-grid>
</template>

reverse also accepts an array of breakpoint names to apply the reversal only at those sizes:

vue
<nb-grid :dir="{ md: 'col' }" :reverse="['md']">...</nb-grid>

Use the visible prop to show or hide grid items. It accepts a boolean or a breakpoint map for responsive control.

Hidden item ​

vue
<template>
  <nb-grid dir="row">
    <nb-grid dir="col" :visible="false">Hidden</nb-grid>
    <nb-grid dir="col">Visible</nb-grid>
  </nb-grid>
</template>

Responsive visibility ​

vue
<template>
  <nb-grid dir="row">
    <!-- Hidden on small, visible on large -->
    <nb-grid dir="col" :visible="{ sm: false, lg: true }">Sidebar</nb-grid>
    <nb-grid dir="col" grow>Main content</nb-grid>
  </nb-grid>
</template>

Props ​

PropTypeDefaultDescription
dir'row' | 'col' | ResponsiveMap | Fn'row'Main axis direction
gapGapToken | ResponsiveMap | Fn-Gap between children
gridnumber | ResponsiveMap | Fn-Number of columns to span (1–16)
shiftnumber | ResponsiveMap | Fn-Column offset from the left edge
justifyJustifyValue | ResponsiveMap | Fn-Horizontal alignment of children
alignAlignValue | ResponsiveMap | Fn-Vertical alignment of children
distributedbooleanfalseChildren grow equally to fill width
wrap'wrap' | 'nowrap' | 'reverse' | ResponsiveMap | Fn-Wrapping behaviour
growbooleanfalseFlex-grow: child expands to fill remaining space
visibleboolean | ResponsiveMap | FntrueShow or hide the element
firstboolean | string[]falseRender this item visually first; array form per breakpoint
lastboolean | string[]falseRender this item visually last; array form per breakpoint
reverseboolean | string[]falseReverse child order; array form per breakpoint
isstring'div'HTML element tag to render (e.g. 'ul', 'li', 'nav')
mode'wide' | 'narrow' | 'condensed''wide'Predefined gap preset

Gap tokens ​

xxs (2px) · xs (4px) · sm (8px) · md (16px) · lg (24px) · xl (32px) · xxl (48px)

Justify values ​

start · center · end · between · around · evenly

Align values ​

start · center · end · stretch · baseline

Breakpoints ​

Mobile-first. Rules at sm apply from 320px up; later breakpoints override earlier ones.

NameMin-width
sm320px
md672px
lg1056px
xl1312px
xxl1584px

Responsive maps ​

Props that accept a breakpoint map take an object keyed by breakpoint name:

typescript
{ sm?: T, md?: T, lg?: T, xl?: T, xxl?: T }

Function props ​

Props that accept a function are called inside the component's computed class generator. Any reactive refs or stores accessed inside are tracked automatically:

typescript
// TypeScript signatures
type TGridTypeFn = () => 'row' | 'col' | 'row-reverse' | 'col-reverse'
type TGridGapFn = () => 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
// ...same pattern for align, justify, wrap, grid, shift, visible
vue
<script setup lang="ts">
const isExpanded = ref(false)
</script>

<template>
  <nb-grid :dir="() => (isExpanded ? 'col' : 'row')">...</nb-grid>
</template>

Exposed ​

typescript
const gridRef = ref<InstanceType<typeof NbGrid>>()
gridRef.value?.getRef() // → underlying HTMLElement