Table of Contents
Note

This documentation describes the GridLayout Vue component for native UI views, for Xml templates see grid-layout.

GridLayout

A CSS Grid layout container with responsive breakpoint support and a simplified DSL for column/row templates.

Import

import { GridLayout } from '@neos/design-system'

Props

All props default to '' (empty, meaning the CSS property is not set).

Template DSL

The rows, columns, and rowsAuto props accept a space-separated string with the following shorthand values:

DSL value CSS equivalent
* minmax(0, 1fr) — flexible fraction
2* minmax(0, 2fr) — double fraction
fit max-content — fit to content
200 (bare number) 200px — fixed pixels
Any valid CSS track Passed through as-is

Column/Row Template Props

Prop Notes
columns Default column template
columnsSmall Overrides columns on small screens
columnsMedium Overrides columns on medium screens
columnsLarge Overrides columns on large screens
columnsExtralarge Overrides columns on extra-large screens
columnsExtraextralarge Overrides columns on very large screens
rows Default row template
rowsSmall / rowsMedium / rowsLarge / rowsExtralarge Responsive row overrides
rowsExtraextralarge Responsive row override (very large screens)
rowsAuto Auto-generated row size (for implicit rows)
rowsAutoSmall / rowsAutoMedium / rowsAutoLarge / rowsAutoExtralarge Responsive auto-row overrides
rowsAutoExtraextralarge Responsive auto-row override (very large screens)

Gap Props

Prop Type Description
gap Space Default gap between cells
gapSmall / gapMedium / gapLarge / gapExtralarge / gapExtraextralarge Space Responsive gap overrides

Slots

Slot Description
default Grid cell children. Use style="--grid-column-span: n" on children to control the column span

Responsive scope

Prop Type Default Description
breakpointScope 'window' \| 'container' 'window' window (default): breakpoints react to the browser viewport, exactly as today. container: breakpoints react to the grid's own rendered width instead.
thresholdSmall number undefined Custom pixel threshold for the small tier. Undefined keeps the standard value (640).
thresholdMedium number undefined Custom pixel threshold for the medium tier. Undefined keeps the standard value (768).
thresholdLarge number undefined Custom pixel threshold for the large tier. Undefined keeps the standard value (1024).
thresholdExtralarge number undefined Custom pixel threshold for the extralarge tier. Undefined keeps the standard value (1280).
thresholdExtraextralarge number undefined Custom pixel threshold for the extraextralarge tier. Undefined keeps the standard value (1536).

Each threshold* prop is independent: set only the tiers you want to move, the others keep their standard value. Applies in container scope always, and in window scope whenever at least one threshold* prop is set.

Once every tier's value is resolved (custom or standard), they must be non-negative and strictly increasing. An invalid combination is ignored (with a console warning) and the standard thresholds are used instead for that render.

breakpointScope decides once, when the grid is created, whether and how its width gets measured; changing it afterwards on an already-rendered grid has no effect (the same behavior as the DataGrid card-mode-scope prop). To offer a live scope switch — for example in a demo — force Vue to recreate the component instead, such as by changing its :key.

A threshold* prop is different: if the grid already measures its width at creation (container scope, or window scope with at least one threshold* prop set), changing it afterwards still updates the thresholds live. It only has no effect if the grid started without measuring its width at all (window scope with no threshold* prop set at all) — force a recreation via :key in that case too.

Container-scope example

<GridLayout
  breakpoint-scope="container"
  :threshold-small="400"
  :threshold-large="900"
  columns-small="*"
  columns-large="* * *"
  gap="medium"
>
  <Card v-for="item in items" :key="item.id">...</Card>
</GridLayout>

In a narrow panel or modal, this grid picks its column count from its own width — not the browser window's — so it never renders a desktop-width layout inside a space that can't fit it.

Window-scope example with custom thresholds

<GridLayout
  :threshold-small="400"
  :threshold-large="900"
  columns-small="*"
  columns-large="* * *"
  gap="medium"
>
  <Card v-for="item in items" :key="item.id">...</Card>
</GridLayout>

breakpointScope stays at its window default here, but the custom thresholds still apply: the grid keeps reacting to the browser viewport, just at the given thresholds instead of the standard ones.

Performance note

Both container scope and a custom threshold* prop in window scope replace the standard, free CSS media queries with a JavaScript-driven measurement (a ResizeObserver in container scope, a window resize listener otherwise). The cost per grid is small, but avoid enabling either on a very large number of simultaneously-rendered grids (for example, one per row of a long list) — prefer the default window scope without custom thresholds there, since it stays pure CSS.

Usage Examples

Two equal columns

<GridLayout columns="* *" gap="medium">
  <StringFormField property-name="firstName" />
  <StringFormField property-name="lastName" />
</GridLayout>

Three columns: fixed | flexible | fit-content

<GridLayout columns="200 * fit" gap="small">
  <div>Sidebar</div>
  <div>Main content</div>
  <div>Aside</div>
</GridLayout>

Responsive: 1 column on small screens, 3 on large

<GridLayout columns-small="*" columns-large="* * *" gap="medium">
  <Card v-for="item in items" :key="item.id">...</Card>
</GridLayout>

Child spanning multiple columns

<GridLayout columns="* * *" gap="small">
  <StringFormField property-name="title" style="--grid-column-span: 3" />
  <StringFormField property-name="firstName" />
  <StringFormField property-name="lastName" />
  <StringFormField property-name="email" />
</GridLayout>

Column and row spans

Set the column and row spans of a child with --grid-column-span and --grid-row-span in its style, and per breakpoint with --grid-column-span-small, --grid-row-span-medium and so on. A breakpoint without a value of its own takes the value of the smaller breakpoint. See Template directives.

<GridLayout columns="* * * *">
  <div style="--grid-column-span: 4; --grid-column-span-medium: 2; --grid-row-span: 2">Wide and tall cell</div>
  <div :style="{ '--grid-column-span': columnCount }">Computed span</div>
</GridLayout>