---
title: "Breakpoints and ranges"
description: "Token breakpoints and the minmax-* / mm-* range variants."
url: https://docs.systhema.app/next/styling/breakpoints
version: unreleased (main)
docs_index: https://docs.systhema.app/next/llms.txt
---

Systhema replaces Tailwind's default breakpoints with the ones in your tokens, and adds range variants that target one band between two breakpoints. Use the breakpoint prefixes (`md:`, `lg:`) for mobile-first styles, and `minmax-*` (short alias `mm-*`) when a style must apply to one range only.

## Quick reference

The breakpoint prefixes apply from their min width upward:

<!-- generated:utilities screens -->

| Variant | Applies                    |
| ------- | -------------------------- |
| `sm:`   | `@media (width >= 0px)`    |
| `md:`   | `@media (width >= 640px)`  |
| `lg:`   | `@media (width >= 1192px)` |
| `xl:`   | `@media (width >= 1366px)` |
| `2xl:`  | `@media (width >= 1728px)` |
| `3xl:`  | `@media (width >= 2048px)` |

<!-- /generated -->

The range variants apply from one breakpoint up to the next:

<!-- generated:utilities range-variants -->

| Variant       | Applies                                              | Note                                             |
| ------------- | ---------------------------------------------------- | ------------------------------------------------ |
| `mm-sm:`      | `@media (max-width: 639px)`                          |                                                  |
| `mm-md:`      | `@media (min-width: 640px) and (max-width: 1191px)`  |                                                  |
| `mm-lg:`      | `@media (min-width: 1192px) and (max-width: 1365px)` |                                                  |
| `mm-xl:`      | `@media (min-width: 1366px) and (max-width: 1727px)` |                                                  |
| `mm-2xl:`     | `@media (min-width: 1728px) and (max-width: 2047px)` |                                                  |
| `mm-3xl:`     | `@media (min-width: 2048px)`                         |                                                  |
| `minmax-sm:`  | `@media (max-width: 639px)`                          |                                                  |
| `minmax-md:`  | `@media (min-width: 640px) and (max-width: 1191px)`  |                                                  |
| `minmax-lg:`  | `@media (min-width: 1192px) and (max-width: 1365px)` |                                                  |
| `minmax-xl:`  | `@media (min-width: 1366px) and (max-width: 1727px)` |                                                  |
| `minmax-2xl:` | `@media (min-width: 1728px) and (max-width: 2047px)` |                                                  |
| `minmax-3xl:` | `@media (min-width: 2048px)`                         |                                                  |
| `mm-md/xl:`   | `@media (min-width: 640px) and (max-width: 1365px)`  | A `/<breakpoint>` modifier sets the upper bound. |

<!-- /generated -->

The values above are the default tokens. `sm` starts at 0, so unprefixed classes and `sm:` classes are the same thing: the phone styles.

## Basic usage

Write the phone layout without a prefix, then override it as the viewport grows. Switch the preview's viewport between phone (390px), tablet (768px) and desktop (1192px): the grid goes from one column to two to three, and the label shows which breakpoint is active.

```tsx preview iframe height=420 title="Mobile-first breakpoints"
export default function Demo() {
  return (
    <div className="flex w-full flex-col gap-6">
      <p className="flex items-baseline gap-3">
        <span className="text-label color-label">Active breakpoint</span>
        <span className="text-h4 color-heading">
          <span className="hidden mm-sm:inline">sm</span>
          <span className="hidden mm-md:inline">md</span>
          <span className="hidden mm-lg:inline">lg</span>
          <span className="hidden mm-xl:inline">xl</span>
          <span className="hidden mm-2xl:inline">2xl</span>
          <span className="hidden mm-3xl:inline">3xl</span>
        </span>
      </p>
      <div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
        {['One', 'Two', 'Three'].map((label) => (
          <div
            key={label}
            className="flex h-24 items-center justify-center rounded-lg border border-(--color-foundations-surface-border) bg-(--color-foundations-surface-bg) color-heading"
          >
            {label}
          </div>
        ))}
      </div>
      <p className="text-small color-label">grid-cols-1 md:grid-cols-2 lg:grid-cols-3</p>
    </div>
  )
}
```

```html
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">…</div>
```

## Range variants

A mobile-first prefix keeps applying at every larger width. A range variant stops at the next breakpoint: `mm-md:` applies from `md` (640px) up to 1191px and nowhere else, so a tablet-only tweak needs no undo at `lg`.

```tsx preview iframe height=300 title="Range variants"
export default function Demo() {
  return (
    <div className="flex w-full flex-col gap-3">
      <div className="hidden rounded-lg bg-(--color-foundations-primary-bg) p-4 text-(--color-foundations-primary-text) mm-sm:block">
        <code>mm-sm:block</code>: phones only
      </div>
      <div className="hidden rounded-lg bg-(--color-foundations-primary-bg) p-4 text-(--color-foundations-primary-text) mm-md:block">
        <code>mm-md:block</code>: tablets only, gone again at <code>lg</code>
      </div>
      <div className="hidden rounded-lg bg-(--color-foundations-primary-bg) p-4 text-(--color-foundations-primary-text) mm-sm/lg:block">
        <code>mm-sm/lg:block</code>: everything below <code>lg</code>
      </div>
      <div className="hidden rounded-lg border border-(--color-foundations-surface-border) p-4 color-body lg:block">
        <code>lg:block</code>: desktop and up
      </div>
    </div>
  )
}
```

- `minmax-<bp>:` and `mm-<bp>:` are the same variant; the short form is easier to read in long class lists.
- A `/<breakpoint>` modifier sets the upper bound: `mm-md/xl:` applies from `md` up to just below `xl`, and `mm-sm/lg:` covers everything below `lg`.
- The last breakpoint has no upper bound, so `mm-3xl:` behaves like `3xl:`.
- The modifier also takes a pixel value in brackets for a one-off bound: `mm-md/[900]:` applies from 640px to 900px.

## Responsive and state variants

Range variants stack with other variants: `mm-md:hover:underline`, `mm-sm:group-hover:block`, `mm-md:focus-visible:outline-2`. They also combine with [`is-*` variants](https://docs.systhema.app/next/styling/is-variants.md), for example `mm-sm:is-[.active]:font-bold`.

## Customizing

Breakpoints are tokens, not Tailwind config. The min widths come from `config.breakpoints` in your token export, and Systhema writes them into Tailwind's `screens`, so the prefixes and the range variants follow whatever your tokens declare. The default tokens declare `sm`, `md`, `lg`, `xl`, `2xl` and `3xl`, but only `sm`, `md` and `lg` carry sizing tokens; `xl` and up keep the `lg` sizes until you define them in `customTokens.responsiveSizing`. The [breakpoints reference](https://docs.systhema.app/next/reference/tokens/breakpoints.md) lists every min width and design width, and [Responsive sizing](https://docs.systhema.app/next/concepts/responsive-sizing.md) explains how sizes change at each one.

The current breakpoint is also available to CSS as `--breakpoint-current` and `--screen-current` (see [CSS variables](https://docs.systhema.app/next/styling/css-variables.md)).

## Related

- [`is-*` variants](https://docs.systhema.app/next/styling/is-variants.md)
- [Viewport-relative spacing](https://docs.systhema.app/next/styling/viewport-units.md)
- [Responsive sizing](https://docs.systhema.app/next/concepts/responsive-sizing.md)
- [Breakpoints reference](https://docs.systhema.app/next/reference/tokens/breakpoints.md)
