Skip to content

GridLayout ​

A grid of equally important cells: product lists, galleries, dashboards. Cells read row by row. The number of columns follows the container width, or adapts on its own from a minimum cell width. A list mode stacks the cells, with an optional grid / list switcher.

Usage ​

Columns by width ​

By default: 1 column, 2 from 640px, 3 from 1024px.

vue
<template>
  <SuGridLayout :columns="{ base: 1, sm: 2, lg: 3, xl: 4 }">
    <ProductCard v-for="product in products" :key="product.id" :product="product" />
  </SuGridLayout>
</template>

Each value applies up to the next threshold (mobile first). A single number fixes the columns at every width: :columns="4".

Automatic columns ​

min-item-width sets the minimum width of a cell: the grid fits as many columns as it can (auto-fill), with no breakpoint. A cell never grows wider than the container.

vue
<SuGridLayout min-item-width="14rem" gap="sm">
  <MediaTile v-for="item in gallery" :key="item.id" :item="item" />
</SuGridLayout>

Grid or list ​

v-model:view switches to a list ('list'): cells stack in a single column. view-toggle adds a grid / list switcher to the header; the header slot holds the title, result count or filters. The default slot receives view so cells can adapt.

The switcher labels come from the component locale (see useLocale); view-toggle-label, grid-label and list-label replace them.

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

const view = ref<'grid' | 'list'>('grid')
</script>

<template>
  <SuGridLayout
    v-model:view="view"
    view-toggle
    view-toggle-label="Display"
    grid-label="Grid"
    list-label="List"
    items-tag="ul"
  >
    <template #header>
      <h2>Products</h2>
      <p>{{ products.length }} results</p>
    </template>

    <li v-for="product in products" :key="product.id">
      <ProductCard :product="product" :direction="view === 'list' ? 'horizontal' : 'vertical'" />
    </li>
  </SuGridLayout>
</template>

Without view-toggle, the view can still be driven from outside, for instance by your own control in a toolbar: <SuGridLayout :view="view">.

API ​

Props ​

PropTypeDefaultDescription
view (v-model:view)'grid' | 'list''grid'View: in a list, cells stack in a single column
columnsnumber | { base?, sm?, md?, lg?, xl? }{ base: 1, sm: 2, lg: 3 }Columns, fixed or by container width
minItemWidthstring—Minimum cell width (CSS length): automatic columns, overrides columns
align'start' | 'center' | 'end' | 'stretch''stretch'Vertical alignment of the cells in a row (stretch: equal height)
itemsTag'div' | 'ul' | 'ol''div'Element holding the cells: ul or ol for a list (li cells)
viewTogglebooleanfalseShows the grid / list switcher in the header
viewToggleLabelstring'Affichage'Accessible name of the switcher
gridLabelstring'Grille'Label of the "grid" button
listLabelstring'Liste'Label of the "list" button
gap'none' | 'sm' | 'md' | 'lg' | 'xl''md'Gap between cells

Events ​

EventPayloadDescription
update:view'grid' | 'list'View picked in the switcher

Slots ​

SlotPropsDescription
header—Title, result count, filters (next to the switcher)
default{ view }Cells: each direct child is a cell

Responsive behavior ​

Container widthColumns (default value)
< 640px1
≥ 640px2
≥ 1024px3

With min-item-width, the number of columns only depends on the available space. In a list, a single column at every width.

Accessibility ​

  • Reading order: cells read row by row, in DOM order, and so does tabbing. This is the grid to pick when order matters (sorted results, chronological feed).
  • Lists: with items-tag="ul" (or "ol") and <li> cells, screen readers announce the number of items. The list role is set explicitly, since some browsers drop it from lists without bullets.
  • Grid / list switcher: a named group (viewToggleLabel) of two toggle buttons (aria-pressed). Labels never change: only the pressed state tells which view is active.

Publié sous licence MIT.