Two named breakpoints in active use, both above the phone range. Apps
built on this library are expected to be desktop-first: the named set
supports richer layouts on wide displays and identifies when to use a single-pane layout. Smaller
breakpoints (sm, md) are intentionally not part
of the named vocabulary; a single component that wants to stack at narrow
phone widths can still use a one-off @media without joining
the shared set.
The minimum supported application width is lg — 768 px. Narrower application layouts are outside the current support range. Recorded in full on
Browser support: desktop and iPad are supported (iPad on
current iOS Safari only) and phone form factors are deferred, so 768 px is both the narrowest
popular iPad in portrait matching the existing lg breakpoint. This uses the existing breakpoint listed below. Ruled 2026-08-06.
Phone widths are out of the product's scope, not merely out of the named set.
That is why sm and md are absent here: a consequence of the scope ruling
rather than an independent style choice. xs below is a reserved Open Props name this
project has not adopted, and it is not a commitment to 360 px.
| Name | Threshold | Use when |
|---|---|---|
lg / lg-n-above |
48em (768px) |
One-pane layouts can become two-pane: a sidebar appears next to <main>, dialogs are no longer pressed against the viewport edge, side rails can sit beside their primary content. |
xl / xl-n-above |
90em (1440px) |
Use the extra display width for extra columns, side-by-side panes that were stacked, persistent reference content (outline, metadata, secondary panel) instead of a popover. Below this is "laptop"; above this is "wide monitor." |
xxs (240), xs (360), sm (480),
md (768), xxl (1920) are also reserved by name in
Open Props' props.media.css.
Adopt another named breakpoint only when a feature needs it.
@media with range syntax
Modern range syntax (width >= …) is Baseline 2023 and
reads more naturally than min-width / max-width.
Always include the Open Props name in a comment so the rule is greppable
and ready to swap to @media (--lg-n-above) if the project
ever adopts a CSS build step.
The element below carries different background and label per breakpoint. Resize the window past 48em (768px) and 90em (1440px) to see the swap.
@container queries — prefer over @media for component layout
@container (Baseline 2023) reacts to the size of an element's
container, not the viewport. Use it when a component might be placed in
different layouts (a card grid in the main column vs in a side panel)
and should adapt to whatever space it gets.
Reach for @media for page-level shifts (sidebar appears,
content reflow). Reach for @container for component-internal
reflow (column count, label position, density).
Drag the bottom-right corner of the dashed area to resize. The grid reflows when the container itself reaches 28rem and again at 44rem, regardless of viewport width.
Almost every responsive decision is layout, and CSS expresses layout better than JS does. JS-side viewport detection is appropriate only when the decision can't be expressed in CSS — for example, swapping component implementations or attaching different event handlers per viewport.
Until that case appears, no shared viewport.mjs helper exists.
When the first consumer arises, instantiate matchMedia
locally:
Hoist to public/lib/viewport.mjs only when a second
consumer appears. One use site is not enough to justify a shared module.
@custom-media
Open Props ships props.media.css
with @custom-media declarations for every named breakpoint
(--lg-n-above, --xl-n-above, …). These are
not Baseline — without a build step that processes them
via PostCSS
Custom Media, browsers ignore the @custom-media at-rule
and a stylesheet that writes @media (--lg-n-above) never
matches.
Without that build step, write the numeric form
(@media (width >= 48em)) with the Open Props name in a
comment. If the project ever adopts PostCSS, the comment makes a
mechanical swap easy.
<ui-dialog> has a component-internal threshold at
640px (ui-dialog.mjs) where it switches to a slide-up
bottom-sheet presentation. It is independent of these project layout
breakpoints — moving lg or xl does not move it.
--font-size-fluid-* /
--size-fluid-*. See
Tokens — fluid sizing without breakpoints.
lg breakpoint.props.media.css — Open Props' breakpoint declarations.