Read · Grain UI
Docs article
The 'Building an accessible dialog' guide went from a stock Docusaurus page with 105-character lines and five admonitions to a 70ch reading page whose dialog example actually runs, tracing focus and logging every close reason as you use it.
- Persona
- Leo Marchetti, Frontend lead implementing a delete confirmation
- Their goal
- Read the dialog guide once, copy the right snippet and understand the focus and closing rules without hunting.
- Lenses applied
- typeset, colorize, quieter, adapt, harden, delight, clarify
/pristine polish src/pages/docs/dialog.mdxBefore5.5/10

After9.5/10

Verdict
5.5/10 Level 6
Readable, but it is every Docusaurus site: stock green, stock Prism, and five admonitions where one belongs. Lines run past 100 characters on a laptop, the one real warning about backdrop close sits between filler notes and a 'Danger' that contradicts the props table, and the focus rules can only be read about, not tried.
9.5/10 Level 10
A docs page built for reading and for trying. The snippet runs right under the code: open it, Tab, press Esc or click outside, and a four-step trace shows where focus went while a log names the close reason. The props table becomes cards on a phone, and the checklist links back to the section that covers each rule.
Scores
Every Dimension, before and after.
| Dimension | Before | After | Change |
|---|---|---|---|
| Persona fit | 5 | 10 | |
| Hierarchy & clarity | 6 | 10 | |
| Layout & spacing | 5 | 9 | |
| Typography | 5 | 10 | |
| Color & theming | 5 | 9 | |
| Consistency | 7 | 9 | |
| Responsiveness | 6 | 10 | |
| Motion & interaction | 5 | 9 | |
| Accessibility | 6 | 10 | |
| Copy | 6 | 10 | |
| Robustness & performance | 6 | 9 |
The critique
What the red pen found.
Vibe-code tells
- Default Docusaurus green instead of the product's own brand
- No max-width measure on prose (~105ch lines)
- Five admonition types on one page
- Filler admonitions that restate the prose
- Emoji in headings
- Checklist faked with ✅ emoji and <br>
- Copy button hidden until hover
- Props table squeezed on mobile
Lines too long to read
The doc column is Docusaurus's `max-width: 75%` of a 1320px container, so body lines run to ~105 characters at 1440px. Readers lose their place at every line break on a Read page.
Admonition overload
Note, tip, info, warning and danger all appear in one guide, each with an icon and a 5px coloured border-left. Two are filler ('Focus is trapped automatically'), the danger box contradicts the closeOnEsc row in the props table, and the one real warning about backdrop close gets lost.
Could be any Docusaurus site
Default #2e8555 green, the stock navbar, stock Prism github theme and stock footer. Nothing says Grain UI; Leo can't tell this guide from the last five library docs he read.
Focus rules you can only imagine
Initial focus, focus return and close reasons are explained in static snippets. The guide is about behaviour, but there is nothing to open, Tab through or press Esc on.
Props table crushed on phones
The four-column table is `display: block; overflow: auto`, so at 390px the Description column wraps to one or two words per line and Default sits in a narrow strip.
Emoji headings and a fake checklist
The h1 ends in 🚀, the last h2 in ✅, and the checklist is six ✅ lines joined with <br>, so screen readers announce 'check mark button' six times and there is no list to navigate. The copy button stays at opacity 0 until hover, so touch users never see it.
The changes
Before, after, and why.
The report Pristine hands back after a run, with the real values from the two pages above.
| Lens | Before | After | Why |
|---|---|---|---|
| typeset | .doc { flex: 0 0 75%; max-width: 75% } inside a 1320px container (~105ch lines at 1440px) | article { max-width: var(--measure) } with --measure: 70ch | Lines stay at a comfortable 65–72 characters at every viewport width. |
| typeset | Docusaurus defaults: h1 3rem, h2 2rem, h3 1.5rem, all weight 700 in the system font stack | h1 clamp(2.25rem, 1.7rem + 1.6vw, 3rem) at weight 680, -0.032em; h2 1.625rem; h3 1.25rem; Inter with font-optical-sizing: auto | A clear scale makes the guide skimmable, and optical sizing keeps the big title tight and the body open. |
| colorize | Stock Prism github theme: pre { background: #f6f8fa; font-size: 90% }, copy button opacity: 0 until hover | pre code { font-size: 0.875rem; line-height: 1.7; color: #26242f on #f5f4f9 } (dark: #e4e2ee on #1a1922) | Code is the most-copied part of the page, so it gets a readable size, tuned token colours for each theme and a copy button you can see. |
| quieter | 5 admonition kinds (note, tip, info, warning, danger), each with an icon and border-left: 5px solid in its own colour | Two styles: neutral note on --surface-2, semantic warning only for real risk, icon plus title, no stripe | When warnings are rare, the one about backdrop close actually gets read. |
| adapt | Docusaurus defaults: sidebar behind a hamburger drawer, TOC as a collapsed 'On this page' box | Rails are position: sticky; top: var(--topbar). ≤1240px: TOC becomes <details>. ≤900px: nav becomes a <details> 'Docs menu' | The article stays first on every screen size, and navigation and the TOC are one tap away without leaving the page. |
| harden | Icon-only search pill on mobile; props table as display: block; overflow: auto with no label | :focus-visible rings, sr-only search label with ⌘K, props table in a labelled scroll region | The page works by keyboard, and the props table scrolls on small screens instead of crushing its columns. |
| delight | Static code block; the reader has to imagine what focus does | Live example under the snippet: 'Delete atlas-web…' opens a real <dialog>, a 4-node trace (Trigger → Cancel → Delete project → Back to trigger) lights up as focus moves, and a log reads onOpenChange(false) · reason: "escape" | The rules the article explains (initial focus, trap, return focus, close reasons) can be checked by hand in five seconds. |
| harden | Backdrop-close advice in prose only | In the example, a backdrop click is ignored with a 2px nudge and the log 'backdrop click ignored · closeOnBackdrop={false}'; deleting strikes the row and focus lands on 'Undo delete' (returnFocus={listRef}) | The warning callout and the returnFocus section are shown working, not just described. |
| adapt | Props table scrolls sideways on phones | ≤600px: each prop becomes a card with labelled Type and Default (data-label); no horizontal scroll at 320px | Leo can read the API on his phone without panning a table. |
| clarify | Checklist as six ✅ emoji lines joined with <br> | Numbered checklist cards that each link to their section, plus a 'Was this guide helpful?' Yes/No with a live thank-you | Each rule points to where it's explained, so the list doubles as a review tool. |