---
title: "Flex grid"
description: "Wrap items into equal columns with flex-grid, and draw divider lines between them."
requested_language: cs
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/cs/styling/flex-grid
version: unreleased (main)
docs_index: https://docs.systhema.app/cs/llms.txt
---
> This page isn't translated yet. Showing English.


`flex-grid` is a wrapping flex container whose children size themselves as equal columns. Use it instead of CSS grid when you want divider lines between the items: each item draws its own divider, so the lines follow the items as they wrap.

## Quick reference

<!-- generated:utilities flex-grid -->

| Class                          | Styles                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `flex-grid`                    | `& { --tw-flex-grid-gap-x: 0px; --tw-flex-grid-gap-y: 0px; --tw-flex-grid-cols: 1; display: flex; flex-direction: row; flex-wrap: wrap; overflow: hidden; column-gap: calc(var(--tw-flex-grid-gap-x) - 1px); row-gap: calc(var(--tw-flex-grid-gap-y) - 1px); }`<br>`.flex-grid { > * { width: round(down, calc((100% / var(--tw-flex-grid-cols)) - ((var(--tw-flex-grid-cols) - 1) * var(--tw-flex-grid-gap-x)) / var(--tw-flex-grid-cols)), 1px); } }` |
| `flex-grid-col-span-1`         | `width: calc((100% / (var(--tw-flex-grid-cols) / 1)) - ((var(--tw-flex-grid-cols) / 1 - 1) * var(--tw-flex-grid-gap-x)) / (var(--tw-flex-grid-cols) / 1));`                                                                                                                                                                                                                                                                                             |
| `flex-grid-col-span-2`         | `width: calc((100% / (var(--tw-flex-grid-cols) / 2)) - ((var(--tw-flex-grid-cols) / 2 - 1) * var(--tw-flex-grid-gap-x)) / (var(--tw-flex-grid-cols) / 2));`                                                                                                                                                                                                                                                                                             |
| `flex-grid-col-span-3`         | `width: calc((100% / (var(--tw-flex-grid-cols) / 3)) - ((var(--tw-flex-grid-cols) / 3 - 1) * var(--tw-flex-grid-gap-x)) / (var(--tw-flex-grid-cols) / 3));`                                                                                                                                                                                                                                                                                             |
| `flex-grid-col-span-4`         | `width: calc((100% / (var(--tw-flex-grid-cols) / 4)) - ((var(--tw-flex-grid-cols) / 4 - 1) * var(--tw-flex-grid-gap-x)) / (var(--tw-flex-grid-cols) / 4));`                                                                                                                                                                                                                                                                                             |
| `flex-grid-col-span-5`         | `width: calc((100% / (var(--tw-flex-grid-cols) / 5)) - ((var(--tw-flex-grid-cols) / 5 - 1) * var(--tw-flex-grid-gap-x)) / (var(--tw-flex-grid-cols) / 5));`                                                                                                                                                                                                                                                                                             |
| `flex-grid-col-span-6`         | `width: calc((100% / (var(--tw-flex-grid-cols) / 6)) - ((var(--tw-flex-grid-cols) / 6 - 1) * var(--tw-flex-grid-gap-x)) / (var(--tw-flex-grid-cols) / 6));`                                                                                                                                                                                                                                                                                             |
| `flex-grid-cols-1`             | `--tw-flex-grid-cols: 1;`                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-cols-2`             | `--tw-flex-grid-cols: 2;`                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-cols-3`             | `--tw-flex-grid-cols: 3;`                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-cols-4`             | `--tw-flex-grid-cols: 4;`                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-cols-5`             | `--tw-flex-grid-cols: 5;`                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-cols-6`             | `--tw-flex-grid-cols: 6;`                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-divide-black`       | `& > ::after { background-color: #000; }`                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-divide-transparent` | `& > ::after { background-color: transparent; }`                                                                                                                                                                                                                                                                                                                                                                                                        |
| `flex-grid-divide-white`       | `& > ::after { background-color: #fff; }`                                                                                                                                                                                                                                                                                                                                                                                                               |
| `flex-grid-divide-x`           | `&  > * { position: relative; }`<br>`.flex-grid-divide-x  > * { &::after { content: var(--tw-content); position: absolute; top: 0; height: 100%; right: calc(-1 * (var(--tw-flex-grid-gap-x) / 2)); transform: translateX(50%); width: 1px; } }`<br>`.flex-grid-divide-x  > * { &:last-child::after { display: none; } }`                                                                                                                               |
| `flex-grid-divide-x-0`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-x-0  > * { &::after { content: var(--tw-content); position: absolute; top: 0; height: 100%; right: calc(-1 * (var(--tw-flex-grid-gap-x) / 2)); transform: translateX(50%); width: 0px; } }`<br>`.flex-grid-divide-x-0  > * { &:last-child::after { display: none; } }`                                                                                                                           |
| `flex-grid-divide-x-2`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-x-2  > * { &::after { content: var(--tw-content); position: absolute; top: 0; height: 100%; right: calc(-1 * (var(--tw-flex-grid-gap-x) / 2)); transform: translateX(50%); width: 2px; } }`<br>`.flex-grid-divide-x-2  > * { &:last-child::after { display: none; } }`                                                                                                                           |
| `flex-grid-divide-x-4`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-x-4  > * { &::after { content: var(--tw-content); position: absolute; top: 0; height: 100%; right: calc(-1 * (var(--tw-flex-grid-gap-x) / 2)); transform: translateX(50%); width: 4px; } }`<br>`.flex-grid-divide-x-4  > * { &:last-child::after { display: none; } }`                                                                                                                           |
| `flex-grid-divide-x-8`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-x-8  > * { &::after { content: var(--tw-content); position: absolute; top: 0; height: 100%; right: calc(-1 * (var(--tw-flex-grid-gap-x) / 2)); transform: translateX(50%); width: 8px; } }`<br>`.flex-grid-divide-x-8  > * { &:last-child::after { display: none; } }`                                                                                                                           |
| `flex-grid-divide-y`           | `&  > * { position: relative; }`<br>`.flex-grid-divide-y  > * { &::after { content: var(--tw-content); position: absolute; left: 0; width: 100%; bottom: calc(-1 * (var(--tw-flex-grid-gap-y) / 2)); transform: translateY(50%); height: 1px; } }`<br>`.flex-grid-divide-y  > * { &:last-child::after { display: none; } }`                                                                                                                             |
| `flex-grid-divide-y-0`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-y-0  > * { &::after { content: var(--tw-content); position: absolute; left: 0; width: 100%; bottom: calc(-1 * (var(--tw-flex-grid-gap-y) / 2)); transform: translateY(50%); height: 0px; } }`<br>`.flex-grid-divide-y-0  > * { &:last-child::after { display: none; } }`                                                                                                                         |
| `flex-grid-divide-y-2`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-y-2  > * { &::after { content: var(--tw-content); position: absolute; left: 0; width: 100%; bottom: calc(-1 * (var(--tw-flex-grid-gap-y) / 2)); transform: translateY(50%); height: 2px; } }`<br>`.flex-grid-divide-y-2  > * { &:last-child::after { display: none; } }`                                                                                                                         |
| `flex-grid-divide-y-4`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-y-4  > * { &::after { content: var(--tw-content); position: absolute; left: 0; width: 100%; bottom: calc(-1 * (var(--tw-flex-grid-gap-y) / 2)); transform: translateY(50%); height: 4px; } }`<br>`.flex-grid-divide-y-4  > * { &:last-child::after { display: none; } }`                                                                                                                         |
| `flex-grid-divide-y-8`         | `&  > * { position: relative; }`<br>`.flex-grid-divide-y-8  > * { &::after { content: var(--tw-content); position: absolute; left: 0; width: 100%; bottom: calc(-1 * (var(--tw-flex-grid-gap-y) / 2)); transform: translateY(50%); height: 8px; } }`<br>`.flex-grid-divide-y-8  > * { &:last-child::after { display: none; } }`                                                                                                                         |

<!-- /generated -->

## Basic usage

Add `flex-grid` and a column count such as `flex-grid-cols-3`. Every direct child becomes one column wide; a partly filled last row keeps the same column width.

```tsx preview title="flex-grid flex-grid-cols-3"
export default function Demo() {
  return (
    <div className="flex-grid flex-grid-cols-3 w-full max-w-[560px]">
      {['01', '02', '03', '04', '05'].map((label, i) => (
        <div
          key={label}
          className={`grid h-16 place-items-center font-mono text-sm text-white ${i % 2 ? 'bg-theme-700' : 'bg-theme-500'}`}
        >
          {label}
        </div>
      ))}
    </div>
  )
}
```

### Gaps

Set the gap with an arbitrary value or a CSS variable: `flex-grid-gap-[24px]` or `flex-grid-gap-(--gap-md)`. It sets the column and the row gap, and the column widths account for it. The hatched area is the gap.

```tsx preview title="flex-grid-gap-(--gap-md)"
const hatch =
  'bg-[repeating-linear-gradient(315deg,var(--color-foundations-line-muted)_0_1px,transparent_0_50%)] bg-size-[10px_10px]'

export default function Demo() {
  return (
    <div className={`flex-grid flex-grid-cols-3 flex-grid-gap-(--gap-md) w-full max-w-[560px] ${hatch}`}>
      {['01', '02', '03', '04', '05', '06'].map((label) => (
        <div
          key={label}
          className="bg-theme-500 grid h-16 place-items-center rounded-lg font-mono text-sm text-white"
        >
          {label}
        </div>
      ))}
    </div>
  )
}
```

> [!WARNING]
> `flex-grid-gap-{n}` with a spacing-scale value (`flex-grid-gap-4`), `flex-grid-gap-x-*` and `flex-grid-gap-y-*` are currently broken under Tailwind CSS v4 and produce no usable rule. Use the arbitrary form, `flex-grid-gap-[…]` or `flex-grid-gap-(…)`, which sets both directions to the same value.

### Spanning columns

`flex-grid-col-span-{n}` makes an item `n` columns wide, gaps included.

```tsx preview title="flex-grid-col-span-2"
export default function Demo() {
  return (
    <div className="flex-grid flex-grid-cols-3 flex-grid-gap-[16px] w-full max-w-[560px]">
      <div className="bg-theme-700 flex-grid-col-span-2 grid h-16 place-items-center rounded-lg font-mono text-sm text-white">
        flex-grid-col-span-2
      </div>
      {['02', '03', '04'].map((label) => (
        <div
          key={label}
          className="bg-theme-500 grid h-16 place-items-center rounded-lg font-mono text-sm text-white"
        >
          {label}
        </div>
      ))}
    </div>
  )
}
```

### Dividers

`flex-grid-divide-x` draws a vertical line in the middle of the gap after each item, and `flex-grid-divide-y` a horizontal line under each item. Set the width with a suffix (`-0`, `-2`, `-4`, `-8`; the bare class is 1px) and the color with `flex-grid-divide-{color}`. The container clips its overflow, so the line after the last item of a row falls outside it and is not drawn, and the last item draws none at all.

The dividers are `::after` elements whose `content` comes from Tailwind's `--tw-content` variable. Tailwind only defines that variable when a project uses a `content-*` utility somewhere, so add `*:after:content-['']` to the container to be sure the lines render:

```tsx preview title="flex-grid-divide-x"
export default function Demo() {
  return (
    <div className="flex-grid flex-grid-cols-3 flex-grid-gap-[48px] flex-grid-divide-x flex-grid-divide-(--color-foundations-surface-border) w-full max-w-[600px] *:after:content-['']">
      {[
        ['12k', 'Pages served'],
        ['98%', 'Lighthouse score'],
        ['4', 'Languages'],
      ].map(([value, label]) => (
        <div key={label} className="flex flex-col gap-1">
          <span className="text-h3 color-heading">{value}</span>
          <span className="text-small color-body">{label}</span>
        </div>
      ))}
    </div>
  )
}
```

```tsx preview title="flex-grid-divide-y-2"
export default function Demo() {
  return (
    <div className="flex-grid flex-grid-cols-1 flex-grid-gap-[24px] flex-grid-divide-y-2 flex-grid-divide-black/20 w-full max-w-[420px] *:after:content-['']">
      {['Tokens', 'Components', 'Payload blocks'].map((label) => (
        <p key={label} className="text-body color-body">
          {label}
        </p>
      ))}
    </div>
  )
}
```

Each item has one `::after`, so `flex-grid-divide-x` and `flex-grid-divide-y` cannot be combined on one container; the class that comes later in the CSS wins.

The colors that work are `black`, `white` and `transparent`, an arbitrary value (`flex-grid-divide-[#d4d4d4]`) or a CSS variable (`flex-grid-divide-(--color-foundations-surface-border)`), each with an optional opacity modifier (`flex-grid-divide-black/20`).

> [!WARNING]
> `flex-grid-divide-base-*` and `flex-grid-divide-theme-*` (the token color primitives) are currently broken: `flex-grid-divide-base` and `flex-grid-divide-theme` emit invalid CSS, and the shaded forms such as `flex-grid-divide-base-300` produce no rule. Pass the token through its variable instead: `flex-grid-divide-(--color-base-300)`.

## Responsive and state variants

Every `flex-grid-*` utility takes breakpoint prefixes. A common pattern is one column on phones and more from a breakpoint up:

```tsx preview iframe height=320 title="flex-grid-cols-1 md:flex-grid-cols-2 lg:flex-grid-cols-4"
export default function Demo() {
  return (
    <div className="flex-grid flex-grid-cols-1 flex-grid-gap-[16px] w-full md:flex-grid-cols-2 lg:flex-grid-cols-4">
      {['01', '02', '03', '04'].map((label) => (
        <div
          key={label}
          className="bg-theme-500 grid h-16 place-items-center rounded-lg font-mono text-sm text-white"
        >
          {label}
        </div>
      ))}
    </div>
  )
}
```

State variants work too, for example `hover:flex-grid-divide-black` to darken the lines while the pointer is over the grid.

## Customizing

The table lists counts and spans from 1 to 6, but any whole number works (`flex-grid-cols-12`, `flex-grid-col-span-8`). The divider widths come from Tailwind's divide-width scale. The gap takes any length, so pass a token variable such as `--gap-md` or `--grid-default-gap` to stay on the token scale (see [Gap](https://docs.systhema.app/cs/styling/gap.md)).

## Related

- [Grid](https://docs.systhema.app/cs/styling/grid.md)
- [Gap](https://docs.systhema.app/cs/styling/gap.md)
- [Columns](https://docs.systhema.app/cs/components/columns.md)
