Responsive design

Adapt layouts across screen sizes with Reva's breakpoint scale, mobile-first utilities, and the responsive-prop API on layout primitives.

Reva is mobile-first. Unprefixed utilities apply at every width; breakpoint prefixes (md:, lg:, …) layer overrides on from that width up. Design the base case for the smallest screen, then add breakpoints to adapt as the viewport grows.

// Stacks on phones, switches to a row from md (1024px) up.
<div className="flex flex-col md:flex-row">…</div>

The breakpoints are a single, token-driven scale — defined once in @reva/design-tokens (core/foundation/breakpoint.json--breakpoint-*) and shared by every web app and Figma. There is no separate per-app breakpoint set.

The breakpoints

PrefixMin-widthTokenTypical target
xs:480px30remLarge phones in landscape
sm:768px48remTablets in portrait
md:1024px64remTablets in landscape, small laptops
lg:1280px80remLaptops and desktops
xl:1536px96remLarge desktops
2xl:1920px120remFull HD displays
3xl:2560px160remUltra-wide / QHD+

The scale aligns with Tailwind's defaults — Reva's smxl carry Tailwind's md2xl pixel values (768 / 1024 / 1280 / 1536) — extended with an xs step below for finer small-screen control and 2xl / 3xl above for large and ultra-wide displays. Reach for 2xl for typical large-desktop layouts; reserve 3xl for genuinely ultra-wide canvases. See the design-tokens Breakpoints page for the live token values.

Working mobile-first

Every responsive utility is a min-width rule. Style the base (unprefixed) for small screens, then override upward:

import { Container, Grid } from "@reva/ui";

// 1 column on phones → 2 from sm → 3 from lg.
<Container>
  <Grid columns={{ default: 1, sm: 2, lg: 3 }} gap={4}>
    {cards}
  </Grid>
</Container>

Container already applies responsive gutters (px-6 sm:px-8 xl:px-10), so page content gets breakpoint-aware padding without any extra classes.

Responsive props

The layout primitives accept responsive values directly — pass an object keyed by breakpoint instead of a static value. The default key is the base (unprefixed) case; every other key is a breakpoint from the scale above.

import { Stack, Flex, Grid } from "@reva/ui";

// Vertical on phones, horizontal from md up; tighter gap below lg.
<Stack direction={{ default: "vertical", md: "horizontal" }} gap={{ default: 2, lg: 4 }} />

// Flex direction flips at a breakpoint.
<Flex direction={{ default: "column", lg: "row" }} />

// Grid grows its column count as the viewport widens.
<Grid columns={{ default: 1, sm: 2, xl: 4 }} gap={6} />

Which primitives expose responsive props:

ComponentResponsive props
Stack / HStack / VStackdirection, gap
Flexdirection, gap
Gridcolumns, rows, gap

The same props also accept container-query keys (@sm, @md, …) to respond to the width of a containing element rather than the viewport — see Container queries for when to reach for those.

Typography stays static

Heading and Text size is not responsive by design — a single value, not a per-breakpoint object. For fluid hero type, pair a base size with a CSS clamp() rather than stacking breakpoint text utilities:

// Fluid headline that scales smoothly between 2rem and 3rem.
<Heading size="5xl" style={{ fontSize: "clamp(2rem, 1.5rem + 2.5vw, 3rem)" }}>
  Intelligent orchestration for modern wealth
</Heading>

The static size props on other components (Button, Input, Badge, …) are likewise fixed per instance — choose the size that fits each context rather than varying it by breakpoint.

On this page