Skip to content

Spacing & layout

A 4-pixel grid, a short list of steps that do real work, and layout rules that keep density consistent from a settings form to a dashboard.

Consistent spacing is invisible when it works and obvious when it doesn't. prfct builds every component and pattern on a 4px grid and uses a deliberately short list of steps, each with a job.

Invite teammate

They'll get an email with a link.

The scale

Spacing uses Tailwind's numeric scale, where one unit is 4px (p-4 is 16px). The whole scale is available, but these steps carry the system:

2px
4px
6px
8px
12px
16px
20px
24px
32px
40px
48px
64px
96px
128px

Rules of rhythm

Proximity is grouping. Related elements sit closer together than unrelated ones. A label is 8px from its input; fields are 20px apart; sections are 48px apart. If two things need a divider to look separate, they probably need more space instead.

Inside smaller than outside. Padding inside a container is smaller than the space around it. A card with 20px padding sits in a grid with 24px gaps or more.

Use gap, not margins. Components never set outer margins; parents arrange children with flex or grid gap. This keeps components reusable in any layout and removes margin-collapsing surprises.

// Preferred
<div className="flex flex-col gap-5"></div>

// Avoid — spacing that belongs to the parent leaks into children
<div className="space-y-5"></div>

Density

Controls share five heights, so anything placed on a row aligns without effort:

SizeHeightUse
xs28pxDense tables and toolbars. Pointer-first UI only.
sm32pxSecondary controls, compact forms, card headers.
default36pxMost controls in product UI.
lg40pxPrimary forms, touch-first surfaces.
xl48pxMarketing calls to action.

Choose a density per surface, not per component: a data-heavy table page may use sm throughout; an onboarding flow may use lg.

Layout

Breakpoints

prfct uses mobile-first breakpoints: unprefixed classes apply everywhere, prefixed ones apply from that width up.

PrefixMin widthTarget
sm:40rem · 640pxLarge phones, landscape.
md:48rem · 768pxTablets, portrait.
lg:64rem · 1024pxTablets landscape, small laptops.
xl:80rem · 1280pxLaptops and desktops.
2xl:96rem · 1536pxLarge desktops.

Containers and gutters

  • Page gutters: 16px on phones, 24px from sm, 32–40px on wide screens.
  • Reading width: long text is capped at 65–75 characters (max-w-prose, max-w-2xl).
  • App shell: a fixed sidebar (240–260px) and a fluid content area; content pages center at max-w-5xl, data pages use the full width.

Container queries

Components that change layout based on their own size — not the viewport — use container queries. FieldGroup is a container, so a responsive field switches from stacked to side-by-side when its column is wide enough, whether that column is a full page or a narrow sheet.

<FieldGroup>
  <Field orientation="responsive"></Field>
</FieldGroup>

Layering

Stacking is a token, too. Overlays portal to the end of the document and use the layer that matches their role, so a select opened inside a dialog always appears above it.

Tokenz-indexUse for
z-base0Document flow.
z-raised10Sticky table headers, floating action rails.
z-sticky20Sticky page headers and toolbars.
z-overlay40Modal scrims.
z-modal50Dialogs, sheets, drawers.
z-popover60Menus, popovers, selects (above modals).
z-toast70Notifications.
z-tooltip80Tooltips — always on top.