Responsive Scaling
Configure responsive Tailwind tokens with the local helper.
Responsive scaling is configured in tailwind.config.ts through the local
tailwind-helper. Current projects still use Tailwind v3, so the helper config
is the source of truth for Tailwind screens, design token values, and how those
values move between screens.
The usual pattern is to author real design values at BASE and one key desktop
breakpoint, then let the helper fill the intermediate and wide-screen values.
That keeps components on stable classes such as p-8, gap-grid-gutter,
rounded-lg, and type-title-xl, while the generated CSS adjusts the actual
size continuously as the viewport changes.
Standard Config
responsiveTheme({
screens: { sm: 600, md: 900, lg: 1200, xl: 1600, xxl: 2000 },
breakpoints: ["lg"],
interpolate: {
sm: {},
md: { base: "sm", lerp: true },
lg: { base: "lg", lerp: true },
xl: { base: "lg", scale: 1.2, lerp: true },
xxl: { base: "lg", scale: 1.3 },
},
spacing: {
BASE: {
4: 12,
8: 32,
},
lg: {
4: 16,
8: 56,
},
},
})screens defines the normal Tailwind min-width breakpoints. BASE is not a
Tailwind screen; it is the value before any screen media query applies.
breakpoints lists the screens that need explicit token maps. With
breakpoints: ["lg"], token families such as spacing, size,
borderRadius, and typography.styles normally define BASE and lg. The
other screens are generated from those anchors.
interpolate describes how each screen gets its value:
| Entry | Meaning |
|---|---|
sm: {} | Carry the current value at 600px. This is usually still the BASE value. |
md: { base: "sm", lerp: true } | Start a smooth ramp at 900px, from the sm value toward the next screen value. |
lg: { base: "lg", lerp: true } | Use the authored lg value at 1200px, then ramp toward xl. |
xl: { base: "lg", scale: 1.2, lerp: true } | Use the lg value scaled up for 1600px, then ramp toward xxl. |
xxl: { base: "lg", scale: 1.3 } | Use the lg value scaled up for 2000px and above. |
lerp applies to the segment that starts at that screen. For example, md
starts the 900px -> 1200px ramp, and lg starts the 1200px -> 1600px
ramp.
How Values Are Generated
For each token, the helper walks the screens in order:
- Read the current screen's
base. - If that base has an authored token value, use it.
- If it does not, carry the previously resolved value.
- Apply
scalewhen present. - If
lerpis true, emit a fluid value that reaches the next screen's value at the next screen width.
Using the spacing.8 example above, the generated shape is:
:root {
--spacing-8: 32px;
}
@media (min-width: 900px) {
:root {
--spacing-8: calc(32px + (100vw - 900px) / 300 * 24);
}
}
@media (min-width: 1200px) {
:root {
--spacing-8: calc(56px + (100vw - 1200px) / 400 * 11.2);
}
}
@media (min-width: 1600px) {
:root {
--spacing-8: calc(67.2px + (100vw - 1600px) / 400 * 5.6);
}
}
@media (min-width: 2000px) {
:root {
--spacing-8: 72.8px;
}
}There is no sudden jump at 900px, 1200px, or 1600px: each ramp starts at
the value already on screen and ends at the value the next media query starts
with.
Smooth Versus Stepped
Without interpolation, the site keeps one value until the next breakpoint and then snaps to the new value. With interpolation, the value changes gradually across the viewport range.
The interpolated line reaches the same anchor values as the stepped line, but it travels between them instead of snapping at each breakpoint.
Why This Works Well
Most designs have a strong mobile composition and a strong desktop composition. The awkward part is everything between them. If spacing, control sizes, radii, and type all jump at a single breakpoint, the page can feel like it rebuilds itself while the browser is being resized.
The helper avoids that by treating breakpoints as anchors, not cliffs. The
BASE and lg values still preserve the design decisions. The interpolation
config simply describes how to travel between those decisions, and the wide
screen scale values keep large displays from feeling like the same desktop
layout stretched across too much space.
Because the same interpolation map is used by spacing, size, radius, and typography tokens, their relationships stay coordinated. A card's padding, its gap, its corner radius, and the heading inside it can all resize through the same viewport ranges without each one inventing a separate breakpoint behavior. Grid gutters and margins can join the same rhythm by referencing spacing variables in the grid config.
Different tokens can have different authored values, but they still move through the same breakpoint rhythm.
Practical Rules
- Keep
screensin ascending order and treat names likemdorlgas layout ranges, not device names. - Keep
breakpointsshort. Most sites only needBASEandlgtoken maps. - Put actual design decisions in
BASEand each key breakpoint. Use interpolation for the in-between screens. - Use
scalefor wide screens when a project should breathe more atxlandxxl; omit it when the desktop composition should stay fixed. - For grid gutters and margins, reference spacing variables when they should scale with the token system.
- Prefer token classes in components. If a value should scale with the system,
add it to
spacing,size,borderRadius, ortypography.stylesinstead of hard-coding a one-off responsive value.