4.8 Cheat Sheet & Cookbook
Every class name on this page is grep-verified against
packages/styles/_standard-50-utilities.scss and _standard-04-grid.scss —
nothing aspirational, nothing renamed-and-forgotten. If a class isn’t real,
it isn’t here.
Directive: This is an operational summary. For exhaustive specifications, consult the full utilities documentation.
Keyboard Shortcuts
Shift + Cmd/Ctrl + D # Open/close Inspector
Shift + Cmd/Ctrl + S # Toggle debug mode (baseline grid, rhythm overlay)
ESC # Close Inspector
The naming pattern
Almost everything follows [property]-[scale], where scale is one of
two interchangeable systems:
- T-shirt:
3xs · 2xs · xs · sm · base · lg · xl · 2xl · 3xl · 4xl · 5xl · 6xl - Numeric rhythm units: no suffix at all = 1 unit (
.mtalone), then
2through12for multiples, plushalfandtrimfor fractions - Always available:
0,auto,full
So .mt-lg, .mt-2, .mt-half, .mt-auto, .mt-full, .mt-0 are all
valid — same pattern for every prefix below. sm: prefixes the mobile
(≤768px) responsive variant of a class where it exists.
Spacing
| Prefix | Property |
|---|---|
m / mt / mr / mb / ml |
margin (all / top / right / bottom / left) |
mx / my |
margin-inline / margin-block |
p / pt / pr / pb / pl |
padding (all / top / right / bottom / left) |
px / py |
padding-inline / padding-block |
gap / gap-x / gap-y |
gap / column-gap / row-gap |
<!-- Space flex/grid children — never margin on children -->
<div class="flex gap-2">
<button>One</button>
<button>Two</button>
</div>
<!-- Mobile-only spacing override -->
<section class="p-xl sm:p-base">Generous on desktop, tight on mobile</section>
Rule: gap on the parent, not margin on the children — margin creates
edge spacing on the first/last item that you then have to fight.
Width & the reading column
| Class | Maps to |
|---|---|
w-* / h-* |
width / height, full scale |
min-w-* / max-w-* / min-h-* / max-h-* |
min/max width/height, full scale |
max-w-mobile / -small / -large / -wide |
capped at a breakpoint (--mobile/--small/--large/--wide) |
max-w-line |
capped at reading width (--line-width, ~42rem) |
max-w-full / -screen / -none |
100% / 100vw / uncapped |
<!-- Reading-width column, centered, outside .prose -->
<article class="max-w-line mx-auto">
<p>Long-form content stays at a comfortable line length...</p>
</article>
Inside .prose, p/h1–h6/li are already capped to --line-width
automatically — you don’t need max-w-line there. It’s for the cases
outside .prose where you still want a readable column (see
Standard::Design §2.4 for how .prose‘s own
grid and breakout classes — .feature, .editorial, .hero, .full —
work).
Prose layout
.prose has no width or alignment of its own — it inherits both from what
surrounds it. Three separate questions, three separate knobs.
Is it centered?
Centered by default — .prose sits inside body, which centers itself
with margin-inline: auto. Nothing to do.
<!-- Flush left instead — zeroes margin-inline and drops the grid's
mirrored gutters, so content hugs the box's own left edge -->
<main class="prose left">
<h1>Title</h1>
<p>This column no longer centers itself.</p>
</main>
How wide can it get?
Two independent tokens (not text-align, not a .prose-specific width
class):
| Token | Controls | Set via |
|---|---|---|
--body-max-width |
The whole page shell, and the ceiling .prose, .hero/.full grow into |
frontmatter (body-max-width: 600px) or :root { --body-max-width: ... } |
--line-width |
The actual paragraph/heading column inside .prose |
frontmatter (line-width: 32rem) or :root { --line-width: ... } |
---
# In a note's frontmatter — scoped to that one note
title: A narrower note
body-max-width: 600px
line-width: 30rem
---
/* In a layout's own <style> — scoped to that page/app, matches how
the Guide/Editor/Manual document shells do it */
:root {
--body-max-width: 100%;
--line-width: 60rem;
}
I want full manual control — some elements narrow, some wide, on purpose
.left and the two width tokens above cover “centered vs. flush-left” and
“one width for everything.” For genuinely different widths per element
type — say, quotes deliberately wider than paragraphs, with no tiered
system deciding it for you — drop .prose‘s grid entirely and take over
by hand. This is exactly how the international theme does it:
.prose {
display: block;
}
.prose :is(p, pre, details, li, hr, .scroll, .callout, aside) {
max-width: 30rem;
margin-inline: 0;
}
The moment .prose isn’t a grid, grid-column/grid-template-columns
become inert everywhere — so anything you don’t list in that :is(...)
selector (blockquote, in this example) falls through with no width cap
at all, and expands to fill .prose‘s own box (--body-max-width). That’s
not a gap to patch — it’s the mechanism: leave an element type out on
purpose, and it gets to be as wide as the page allows. This is the way to
get a pull-quote or a .feature-style block to read meaningfully wider
than the surrounding prose, with every element type’s width an explicit
decision instead of something the grid’s tiers pick for you.
One gotcha: the framework’s own blockquote/.callout/pre/figure
rule still applies a small margin-inline: var(--content-width-sm)
(~1 baseline) even with the grid disabled — margin isn’t grid-dependent,
so it survives display: block. If you want an omitted element flush to
the page edges rather than inset by that leftover margin, zero it
explicitly: add margin-inline: 0 to your own override for that element.
How do I center the title?
h1 isn’t centered by the layout system itself — that’s a text-align
job, same as any other text:
<h1 class="text-center">Article Title</h1>
If every title on the site should be centered, that’s a theme decision,
not a per-note one — the garden theme already does this by default
(h1 { text-align: center } scoped to [data-theme="garden"]). Use the
utility when you want to override a specific title against the current
theme’s default, not to set the site-wide behavior.
Grid & columns
<div class="grid">
<div class="col-4 sm:col-12">Card</div>
<div class="col-4 sm:col-12">Card</div>
<div class="col-4 sm:col-12">Card</div>
</div>
.grid— 12-column container. Direct children use.col-1….col-12..sm:col-*— override at ≤768px..lg:col-*— override at ≥1024px..start-{n}— start a column at line n (for asymmetric layouts)..grid.compact/.grid.relaxed/.grid.no-gap— tighter, wider, or
zero row-gap.
Ratios: .col-6+.col-6 (equal halves) · .col-8+.col-4
(content+sidebar) · .col-4×3 (thirds).
Flexbox
<div class="flex items-center justify-between">
<span>Left</span>
<span>Right</span>
</div>
<!-- Same thing, shorter: -->
<div class="flex-far">
<span>Left</span>
<span>Right</span>
</div>
.flex/.flex-row/.flex-col/.flex-wrap/.flex-nowrap/.flex-1.items-{start,center,end,baseline,stretch}/.justify-{start,center,end,between,around,evenly}.flex-far— shorthand forflex+items-center+justify-between(toolbars, header rows)
Typography
<p class="text-sm text-muted">Posted 2 hours ago</p>
<span class="uppercase text-xs">Category</span>
<p class="ellipsis" style="max-width: 200px;">Truncates with an ellipsis…</p>
- Size:
.text-{3xs, 2xs, xs, sm, base, lg, xl, 2xl…6xl} - Align:
.text-{left, center, right, justify}(sm:text-centerfor mobile-only) - Color:
.text-{accent, muted, subtle, primary} - Family/weight:
.font-{sans, serif, monospace, bold, light, normal} - Transform:
.uppercase,.lowercase,.capitalize - Behavior:
.ellipsis(needs amax-widthto truncate against),.no-wrap
Color & surface
<div class="bg-surface p-base">Panel with subtle background</div>
<span class="text-accent">Highlighted text</span>
- Backgrounds:
.bg-{accent, surface, surface-low, surface-high, surface-lowest, surface-highest, glass, transparent}+ hue names (red, orange, yellow, green, cyan, blue, purple, pink) - Text:
.text-{accent, muted, subtle, primary}— no bare.muted/.accent, alwaystext-prefixed
Borders, radius, shadow
.border/.border-0/.border-{t,r,b,l}/.border-accent.rounded-{sm, lg, xl, full, 50}—.rounded-50is a true circle (also applies to a nestedimg).shadow-{lg, xl, raised, inset, inset-ring, ring, glow}
Centering
Three real mechanisms — there’s no bare .center:
<!-- Flex-center everything inside -->
<div class="center-content"><p>Centered in both directions</p></div>
<!-- Auto-margin a block with a defined width -->
<div class="max-w-line center-horizontally">Centered column</div>
<!-- Text-align (words, not the box) -->
<h1 class="text-center">Centered heading</h1>
Debugging: not centering? .center-horizontally needs the element to
already have a bounded width (max-w-*, w-*, or an intrinsic width) —
auto-margins have nothing to distribute on a full-width block.
Visibility & responsive
<span class="visually-hidden">Opens in new tab</span>
<div class="sm:hidden">Desktop-only content</div>
<div class="lg:only">Desktop-only, hidden below 1024px</div>
.hidden—display: none, gone from everyone.visually-hidden— hidden visually, still read by screen readers.sm:hidden/.sm:only— hide/show at ≤768px.lg:hidden/.lg:only— hide/show at ≥1024px
Recipes
Card grid (responsive, 3 → 1 column)
<div class="grid gap-2">
<article class="col-4 sm:col-12 p-base border rounded-lg">
<h3>Card 1</h3>
<p class="text-sm text-muted">Description</p>
</article>
<article class="col-4 sm:col-12 p-base border rounded-lg">
<h3>Card 2</h3>
</article>
<article class="col-4 sm:col-12 p-base border rounded-lg">
<h3>Card 3</h3>
</article>
</div>
Centered article (the 90% pattern)
<div class="max-w-line center-horizontally p-base">
<h1>Page Title</h1>
<p>Text stays at optimal width. Container is centered.</p>
</div>
Toolbar (title left, actions right)
<div class="flex-far p-base border-b">
<h2 class="text-lg">Section Title</h2>
<div class="flex gap-2">
<button>Cancel</button>
<button class="bg-accent">Save</button>
</div>
</div>
Sidebar + content (2:1 ratio)
<div class="grid gap-2">
<main class="col-8 sm:col-12">
<article class="max-w-line">
<h1>Article Title</h1>
<p>Main content...</p>
</article>
</main>
<aside class="col-4 sm:col-12">
<h3>Related</h3>
</aside>
</div>
Accessible icon link
<a href="https://external.com" target="_blank">
Read more
<span class="visually-hidden">Opens in new tab</span>
</a>
Avatar (circle image)
<img class="rounded-50" src="/avatar.jpg" width="48" height="48" alt="" />
Common mistakes
gapwith nodisplay: flex/grid—gapis silently ignored on a block element. Always pair it with.flexor.grid.- Margin on flex/grid children instead of
gap— creates uneven edge spacing (first/last child has no partner to collapse against). - Reaching for inline
style="max-width:...; margin:0 auto"when.max-w-line.center-horizontally(or.max-w-*+.center-horizontally) already does it, self-documenting. .sm:col-12without a base.col-*— the mobile override needs something to override; always set the desktop-first class too (.col-4 sm:col-12, not just.sm:col-12).
Remember
[property]-[scale] is the whole grammar. If a class isn’t listed above,
check the full utilities documentation before
reaching for an inline style — it’s very likely already there under a name
you haven’t guessed yet.