Fluid Design System
Every block in the library shares a design system that handles spacing, typography, and responsive behavior. This page explains how it works, why it is built this way, and how to customize it.
You do not need to read this page to use blocks — everything works out of the box. But if you want to adjust the spacing, understand why blocks look consistent together, or customize the system for your project, this is where to look.
Why Fluid?
Traditional responsive design relies on breakpoints — fixed screen widths where values change abruptly. A section might use one amount of padding on mobile, a larger amount on tablet, and an even larger amount on desktop. This creates two problems.
Consistency is hard to maintain. When every block defines its own responsive spacing, blocks built at different times end up with slightly different values. Stack five of them on a page and the vertical rhythm feels uneven — someone has to go through each block and manually align the spacing. That work gets repeated on every project.
The transitions are not smooth. At one screen width the spacing is one value; one pixel wider and it jumps to a completely different value. On the growing range of screen sizes that fall between traditional breakpoints, the design just defaults to whatever the smaller breakpoint dictates.
How Fluid Design Solves This
Instead of jumping between fixed values at breakpoints, fluid design scales spacing and font sizes smoothly as the screen gets wider or narrower. A section that needs 32 pixels of padding on a small phone and 72 pixels on a large desktop gets every proportional value in between — automatically. No jumps, no manual overrides.
This is done with a CSS function called clamp() that calculates the right value for any screen width:
1/* Spacing that scales from 32px (at 360px screen width) to 72px (at 1440px screen width) */
2--space-l-2xl: clamp(2rem, 1.3376rem + 3.231vw, 4.5rem);You do not need to write or understand these values. They are pre-generated and stored in a CSS file (tokens.css) that you copy into your project once during setup. Blocks reference these values through readable names like my-section or gap-stack — you never interact with the math directly.
The key benefit: every block that uses the same spacing token gets exactly the same spacing at every screen size. Stack a hero, a features section, and a CTA on a page — the rhythm between them is consistent because they all draw from the same scale.
Breakpoints are still used for structural layout changes — like stacking a two-column grid into a single column on small screens. But spacing and font sizes are always fluid. You never need to write responsive spacing overrides for individual blocks.
How the System Is Organized
The fluid design system has three layers, each building on the one before it. You do not need to work with all three directly — most of the time, the React components (Layer 3) handle everything.
Layer 1: CSS Tokens
The foundation is a set of CSS variables in tokens.css, generated using Utopia. These define two scales: a type scale for font sizes and a space scale for padding, margins, and gaps. Every value is a clamp() function tuned to a 360px–1440px screen width range.
On top of the raw scale values, a set of semantic tokens gives meaningful names to common design decisions:
1:root {
2 --fluid-section: var(--space-l-2xl); /* section vertical spacing */
3 --fluid-component-gap: var(--space-s-m); /* gap between items in a component */
4 --fluid-surface-padding: var(--space-m-l); /* padding inside cards and surfaces */
5 --fluid-inline-padding: var(--space-s-l); /* horizontal page margins */
6 --surface-radius: 1.5rem; /* border radius for cards */
7}When you use --fluid-section, you are saying "this is the standard vertical spacing between page sections." The actual pixel value depends on the screen size, but the design intent is always clear.
Layer 2: Tailwind Utility Classes
The CSS tokens work but are verbose to use inline. The second layer provides short, readable Tailwind class names that map directly to the tokens:
| Class | What it does |
|---|---|
my-section | Vertical margin between sections |
gap-stack | Gap between stacked items |
p-surface | Padding inside a card or surface |
px-inline | Horizontal page margins |
One class handles every screen size. No responsive prefixes needed for spacing.
Layer 3: React Components
The third layer is a set of React components that apply the right classes for common layout patterns. These are what blocks actually use.
FluidSection wraps each block in a <section> tag with a max-width container.
FluidGrid provides a 12-column CSS grid inside the section. It accepts props for vertical spacing and optional background color. When a background is set, it automatically adds padding and rounded corners to create a visually distinct surface.
SectionHeader handles the common pattern of an eyebrow label, title, description, and optional buttons below. It supports left and center alignment.
Every block in the library follows the same structure:
1<FluidSection>
2 <FluidGrid marginY={...} bgColor={...}>
3 <div className="col-span-12">
4 <SectionHeader eyebrow={...} title={...} description={...} align={...}>
5 {/* buttons, etc. */}
6 </SectionHeader>
7 </div>
8 {/* block content */}
9 </FluidGrid>
10</FluidSection>Additional components — FluidStack, FluidCluster, FluidContainer, FluidSubGrid, FluidSurface — handle vertical stacking, horizontal wrapping, width constraints, nested grids, and card surfaces. Each one is a thin wrapper over the fluid utility classes.
Design Controls in the Payload Admin
Every block includes a Design section in the Payload admin panel with three controls that content editors can use without touching code:
| Control | What it does | Options |
|---|---|---|
| Spacing | How much vertical space above and below the block | Compact, Comfortable (default), Spacious |
| Background | Section background color | Default (transparent), Muted, Card, Primary, Accent |
| Alignment | Text alignment for the section header | Left, Center (default) |
Spacing maps to different vertical margin values — all still fluid, just at different scales. "Compact" pulls blocks closer together, "spacious" gives them more breathing room.
Background applies a background color using your project's color theme. Choosing "Primary" automatically switches the text to a contrasting color. See Theming for details on how backgrounds work with your color scheme.
Alignment controls whether the section header text is left-aligned or centered.
These controls are added to every block config automatically through shared helper functions, so all blocks get the same design options with no extra setup.
Customizing the System
The entire system inherits from the CSS tokens in tokens.css. To adjust spacing globally, override the semantic tokens in your globals.css:
1:root {
2 --fluid-section: var(--space-2xl); /* tighter section spacing */
3 --fluid-surface-padding: var(--space-s); /* smaller card padding */
4 --surface-radius: 1rem; /* less rounded surfaces */
5}One change propagates through every utility class, every React component, and every block on the page. See Customization for more ways to adapt blocks to your project.
To change the underlying scale — different screen width range, different size ratio — regenerate the tokens using the Utopia calculator and replace the values in tokens.css.
Reference
The tables below list every token, utility class, and component in the system. Use them as a lookup when building or customizing blocks — you do not need to memorize any of this.
Type Scale Tokens
| Token | Min (360px) | Max (1440px) | Usage |
|---|---|---|---|
--step--2 | 11.11px | 11.52px | Fine print |
--step--1 | 13.33px | 14.40px | Small text |
--step-0 | 16.00px | 18.00px | Body text |
--step-1 | 19.20px | 22.50px | H5 |
--step-2 | 23.04px | 28.13px | H4 |
--step-3 | 27.65px | 35.16px | H3 |
--step-4 | 33.18px | 43.95px | H2 |
--step-5 | 39.81px | 54.93px | H1 |
--step-6 | 47.78px | 68.66px | Hero/display |
Space Scale Tokens
| Token | Min → Max | Usage |
|---|---|---|
--space-2xs | 8px → 9px | Tight gaps |
--space-xs | 12px → 14px | Small gaps |
--space-s | 16px → 18px | Component-level gaps |
--space-m | 24px → 27px | Medium spacing |
--space-l | 32px → 36px | Section-level gaps |
--space-xl | 48px → 54px | Large section spacing |
--space-2xl | 64px → 72px | Hero spacing |
--space-3xl | 96px → 108px | Major sections |
Semantic Tokens
| Token | Value | Purpose |
|---|---|---|
--fluid-section | --space-l-2xl | Standard section vertical spacing |
--fluid-section-sm | --space-s-l | Compact section spacing |
--fluid-section-lg | --space-3xl-4xl | Large section spacing |
--fluid-section-xl | --space-4xl-5xl | Extra-large section spacing |
--fluid-component-gap | --space-s-m | Gap between items within a component |
--fluid-surface-padding | --space-m-l | Padding inside card/surface containers |
--fluid-inline-padding | --space-s-l | Horizontal page margins |
--surface-radius | 1.5rem | Border radius for surfaces/cards |
Utility Classes
Section Spacing
| Class | Purpose |
|---|---|
py-section | Standard section vertical padding |
my-section | Standard section vertical margin |
my-section-sm | Compact section margin |
my-section-lg | Large section margin |
my-section-xl | Extra-large section margin |
Component Gaps
| Class | Purpose |
|---|---|
gap-section-items | Gap between major items in a section |
gap-section-inner | Gap between sub-items within a section |
gap-stack-sm / gap-stack / gap-stack-lg | Vertical flex gap variants |
gap-cluster-sm / gap-cluster / gap-cluster-lg | Horizontal flex gap variants |
Surface Padding
| Class | Purpose |
|---|---|
p-surface-sm | Compact surface padding |
p-surface | Standard surface padding |
p-surface-lg | Large surface padding |
Inline Padding
| Class | Purpose |
|---|---|
px-inline-sm | Narrow horizontal margins |
px-inline | Standard horizontal page margins |
bleed-inline | Negative margins to break out of container |
Layout Components
| Component | Purpose | Key Props |
|---|---|---|
FluidSection | Outermost wrapper — <section> + container | className, bgClassName |
FluidGrid | 12-column CSS grid with spacing and optional background | marginY (sm/lg/xl), bgColor, columnGap |
FluidSubGrid | CSS subgrid for nested grid layouts | className |
FluidContainer | Width-constrained container | maxWidth (narrow/wide/full) |
FluidStack | Vertical flex layout | gap (sm/md/lg) |
FluidCluster | Horizontal flex layout (wrapping) | gap (sm/md/lg) |
FluidSurface | Card/surface with radius and padding | padding (sm/md/lg) |
Typography Components
| Component | Purpose |
|---|---|
SectionHeader | Composite: eyebrow + title + description + children slot |
SectionTitle | Standalone section title |
SectionDescription | Standalone description text |
Eyebrow | Small label above a title |
Admin Design Fields
| Field | Options | Default | Purpose |
|---|---|---|---|
spacingPreset | compact, comfortable, spacious | comfortable | Controls FluidGrid vertical margin |
backgroundTheme | default, muted, card, primary, accent | default | Sets section background color |
contentAlignment | start, center | center | Controls text alignment |