Docs

This page isn't translated yet

next

Breakpoints and ranges

Token breakpoints and the minmax-* / mm-* range variants.

On this page

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 referenceLink to this section

The breakpoint prefixes apply from their min width upward:

VariantApplies
sm:@media (width >= 0px)
md:@media (width >= 640px)
lg:@media (width >= 1192px)
xl:@media (width >= 1366px)
2xl:@media (width >= 1728px)
3xl:@media (width >= 2048px)

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

VariantAppliesNote
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.

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 usageLink to this section

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.

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>
  )
}
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">…</div>

Range variantsLink to this section

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.

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 variantsLink to this section

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, for example mm-sm:is-[.active]:font-bold.

CustomizingLink to this section

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 lists every min width and design width, and Responsive sizing explains how sizes change at each one.

The current breakpoint is also available to CSS as --breakpoint-current and --screen-current (see CSS variables).