Documentation blocks
Every component in Grails can have extended usage documentation authored as typed blocks. This documentation is intended for the entire product team — designers, engineers, and product managers — to understand how and when to use each component correctly.
Opening the Documentation Drawer
From any component in the library, click the Book icon (📖) in the header of the Component Details Panel, beside the close button. A token’s and a style’s panel have it in the same place. This opens a secondary Documentation Drawer, stacked on top of the component drawer.
The Book icon is always there.
The drawer is for reading, whatever your role. It shows the documentation and nothing to change it: no Add block, no Save, no controls on the blocks. Documentation is written in Docs. A checklist step cannot be ticked from the drawer either: it is ticked in Docs.
The bar at the bottom of the drawer has Open in Docs, for every role. It opens the entity’s page in Docs: a component’s on its Docs tab, and the page of a token collection, a style or a token. An entity with no page in Docs, such as a flow or a screen, has no bar.
On something with nothing written yet, the drawer says No documentation yet. Admins and editors, on a screen at least 768 pixels wide, also get Edit in Docs, which opens the same page already editing. A viewer sees the message and nothing to click apart from the bar’s Open in Docs.

What Documentation Contains
Documentation is written as typed blocks, not as one free-form body of Markdown. The type of a block is not a label: it is a shape that determines which fields the content has. A rule with a level of obligation is stored with that level as a field, so an audit can read it — not as a word buried in a paragraph.
Pick the shape by what it does, and when two of them fit, by the question it answers.
The Add block menu lists the shapes in this order:
| Block | What it does | Answers | Don’t use it when |
|---|---|---|---|
Title (title) | Inserts a section title with hierarchy levels | What section is this? | You want to write under the heading too — a title carries no body, the prose goes in a Text block below it |
Text (sections) | Displays plain text or bulleted lists | — see the note | See the note below |
Table (table) | Custom tabulated data | How do these values compare? | Each row names something and defines what it is → Specs |
Props (api) | Table with the current Component’s properties | What properties does it have? | Only on a component — it reads the props from the spec |
Specs (specs) | Definitions with option to cross reference them (eg: use A instead of B) | What is this, exactly? | The row prescribes something and carries a level of obligation → Guidelines; if the rows get ticked → Checklist; if you are reading a value across columns → Table |
Guidelines (guidelines) | Complex rules with their usage and reason (eg: MUST NOT use A because..) | How do I use it well? | It helps decide whether to use it → Use cases |
Use cases (use-cases) | Documents Do’s and Dont’s | Should I use this or not? | The reader already decided and just wants to use it well → Guidelines |
Checklist (checklist) | A list of steps that can be checked to reflect status | What do I need to verify? | Nobody will tick them → Guidelines |
Image (image) | Attaches an image with an optional description | What does it look like? | A comparison needs several, each with its own alt text |
File (file) | Supports PDF, PPTX, DOCX with content extraction for auto-indexation | Where is the document? | You could say it in three paragraphs → Text. See the note below |
Figma (figma) | Shows a frame or component from a Figma file, from its link | What does it look like in Figma? | It must not change when the file does → Image. See the note below |
Related (related) | Links this entity to others with a verb and a reason (eg: replaces, pairs with) | What else should I look at? | You are naming something inside a sentence → that is a mention, write it in Text. Only one Related block per entity |
Specs, Table and Guidelines — the three that get confused
Take one subject — spacing — and notice that it wants a different shape depending on what you are actually writing down:
- Specs defines. Each row names something and says what it is, one row at a time: Gap — the space between two items inside a stack. Inset — the space between a container’s edge and its content.
- Table compares. Same subject, but now the rows only mean something read across columns: xs · 4px · 2px, sm · 8px · 4px, md · 16px · 8px. Nobody is being told what a thing is; they are looking up a number.
- Guidelines prescribes. It tells someone what to do, and it carries a level of obligation:
Use
mdbetween form fields (should). Never hardcode a pixel value (must not).
Two tests settle almost every case:
- Specs or Table? Read one row on its own, with the headings covered. “Gap: the space between two items in a stack” still says something — that is a spec. “sm · 8px · 4px” says nothing without its column headings — that is a table.
- Specs or Guidelines? Put must in front of it. “Must: the border is 2 px” is nonsense, so it is a spec. “Must: use a 2 px border” reads perfectly, so it is a guideline.
This is not a matter of taste. A guideline stores its level as a field, which is what lets an audit read it; Specs gives every row a stable identity, which is what lets rows point at each other; a Table keeps columns as columns, so a value stays a value. Content written in the wrong shape looks right on the page and is invisible to everything else.
Specs used to be called Table, and was renamed on 2026-09-08. The old name and its table icon made people pick it when they wanted to lay data out in rows and columns — and then find two fixed fields that do not do that. Existing blocks were converted automatically and nothing was lost; what used to be called Term is now called Spec. The Table block you see today is a different, new shape — the one that actually tabulates.
Pointing one spec at another
Inside a Specs block, a row can point at other rows of the same block, and the reference now says how the two relate: Instead of, Along with, Requires, Replaces, Replaced by or See also. You pick the target from the block’s own rows, so a reference cannot go stale when a row is renamed or translated.
Before this, a reference had no verb and every one of them silently meant instead of. Existing references were kept and are now labelled Instead of explicitly — the meaning did not change, it just stopped being implied.
Tables
Adding a table starts with its size: sweep the grid to say how many rows and columns you want, rather than accepting a default that is wrong most of the time — a breakpoint table is 4×2, a support matrix is 3×6.
From there you edit it in place, on the page, not in a side panel.
- Rows and columns are added and removed around the cell your cursor is in — insert above, insert below, insert to the left, insert to the right, delete this row, delete this column.
- The header row can be turned off and back on. A table does need one to be saved; if you leave it off, Grails tells you before saving rather than failing afterwards.
- Cells take bold and italic, and mentions of other entities, like anywhere else.
- Column widths are dragged, and they stay. Reopen the block a month later and the columns come back the way you left them.
- The title is optional. A table without one is a finished table.
- A cell holds one paragraph. If you put a line break inside a cell, you are asked to remove it before saving.
A table never gets a height of its own: it grows downwards and pushes whatever is below it, so no row is ever hidden behind a scrollbar. Columns share the width available and long text wraps rather than forcing the table wider.
Props — the only one you do not write in full
A Props block does not store the list of properties: it reads them from the component’s spec, live. What you write is the prose for each one — what it is for, what happens if you leave it at its default, which other prop it does not combine with.
That is why it is the only shape that exists on a component and nowhere else: on a token or a style there would be no spec to read from, and the menu does not even offer it.
And it is why it cannot go stale. If someone adds a variant in Figma tomorrow, the row shows up on its own with an empty description; if they remove a property, the row disappears and your text about it is kept in case it returns. The spec owns the structure, you own the judgement.
Example. On a
Button, thesizerow arrives from the spec with itssm · md · lgvalues, and you write: “mdis the default and covers almost everything.smis for dense bars — do not use it as a screen’s primary action — andlgonly on the first action of a landing page.”
Guidelines — rules with a level of obligation
A guideline is a rule with its reason and its weight. The weight is not a word inside the paragraph: it is a field, so an audit can read “this rule is MUST” without interpreting prose.
- MUST — not meeting it is a defect.
- SHOULD — the exception exists and has to be justified.
- MAY — allowed, and it needs no explanation.
Always write the reason. A rule without one is followed while someone remembers it, and dropped the day it gets in the way. With the reason written down, whoever finds it can decide whether the case in front of them is the exception.
Example. “MUST NOT use the commercial Banner inside a payment flow — it competes with the primary action, and there is measured conversion loss at checkout.”
Reach for Guidelines when the reader has already decided to use the thing and wants to use it well. If they are still deciding whether to use it, that is Use cases.
Use cases — what to do and what not to
Use cases is read before deciding; Guidelines, after. That is the whole difference between the two, and it is the most common confusion.
Each item carries a stance — recommended or discouraged — and can point at the alternative. That is what makes it a real do / don’t instead of two paragraphs that say opposite things with nothing relating them.
Example. “Avoid the Context Selector for navigating between different sections of the app — it always keeps one option selected, so it says ‘you are in one of these’, not ‘you are going elsewhere’. Use Tabs for that.”
Write the alternative as a mention of the entity, not as text: that way, the day someone renames
Tabs, your recommendation still points at the same thing.
Checklist — steps someone is going to tick
A Checklist is a list whose state is saved. Ticking an item is not a mental note: it is stored on the block, with its date, and whoever opens the page later sees what has already been done.
That decides when to use it: if nobody is going to tick them, it is not a checklist — it is guidelines with bullets. The question is not whether the content looks like a list, it is whether anyone is keeping count.
Example. An accessibility checklist on a component: “Contrast ≥ 4.5:1 in both themes · Keyboard navigable with no focus trap · The error state is announced, not just painted · The touch target reaches 44×44”.
A step is ticked in Docs, not in the documentation drawer, which is read-only.
Image — and why the alt text is not optional
An Image attaches a file and a description. The description is not a decorative caption: it is what screen-reader users and search read, so an image without text is an image that answers no query.
Describe what the image shows, not what it illustrates. “The component in its error state” is useless; “The field with a red border, the alert icon on the right and the message below it in dark red” works, because someone who cannot see it can reconstruct it.
A comparison — the before and the after, the right way and the wrong way — is two image blocks, each with its own description. A single image with both inside forces you to describe both in one text, and neither is separately searchable.
Section titles
A Title block is a heading and nothing else. You pick its level — H1 through H6 — and everything that follows it, until the next title, reads as its section.
- It carries no body. The prose that belongs under a heading goes in a Text block below it.
- It is one line, and it is not the entity’s name: the page already shows that at the top, which is why a new title starts at H2.
- You see the level, you do not just name it. What you type is rendered at the size the heading will have, so switching from H2 to H4 resizes the text in front of you.
- Nothing is nested. Order alone associates a title with what it titles, exactly as in a written document — move a paragraph above a heading and it belongs to the previous section.
Text is text again
The Text block used to offer headings and a table button. Both are now shapes of their own, so what Text offers is bold, italic, bullet lists and mentions — prose, in other words.
Older Text blocks that already contain a heading or a Markdown table still display and edit correctly; nothing was converted and nothing was lost. What changed is what the toolbar invites you to write from now on.
Mentions in blocks
Type @ to mention an entity inside a Text block, and in the text fields of the other blocks: a table cell, the name or definition of a Specs row, the rule of a guideline, a checklist step, and the description of a prop, an Image or a Figma block. The picker offers components, tokens, token collections, styles, Docs pages and patterns (both published patterns and drafts, marked with their status).
Selecting an entity inserts a mention chip. Clicking it behaves according to its kind:
- Components, tokens and text styles open their side panel.
- A pattern opens its page (and while you are editing a document, it opens in a new tab).
- Docs pages, token collections, and color, effect or grid styles open nothing. Where they show depends on the block:
- In the editor, and in the fields of Title, Table, Props, Specs, Guidelines, Checklist, Image and Figma blocks, they show as a disabled chip with a tooltip.
- In a Text block that you are reading (not editing), they show as plain colored text: no chip, no disabled state and no tooltip.
Attaching a file
Use a File block when the document is the documentation — the brand guidelines PDF, a spec somebody exported — and transcribing it would be busywork. The text inside is pulled out automatically, so the content answers searches just as if it had been typed.
Two things worth knowing before you reach for it:
- A scanned PDF has no text inside it. That is not something the file type tells us — it only shows up once we read the document — and when it happens the file is still attached and still downloadable, but it will not appear in any search. It is an attachment, not documentation.
- The first 30,000 characters are what gets indexed. A longer document uploads fine and is marked as truncated, but anything past that point is not searchable.
Accepted formats are PDF, Word, PowerPoint, Excel and OpenDocument. The older Office formats —
.doc, .ppt, .xls — are refused when you upload them, because there is no reliable way to read
their contents, and an attachment nobody can read is worse than being told up front.
⚠️ Deleting a page or a block deletes its file too, permanently. Unlike documentation attached to a synced component, which is restored on the next sync, there is nothing that brings a page’s file back.
Text is the default destination, not the preferred one. If you find yourself typing ### in a
Text block, that is a Title; if you find yourself drawing a Markdown table in one, that is a
Table. Move it to the shape that stores those fields. Simulated structure looks the same on
screen and is invisible to everything else — search, audits, and the DSDS export.
Showing a frame from Figma
Use a Figma block to show a frame, a component or a screen of a Figma design file. Paste its link: in Figma, select it and use Copy link. The editor tells you at once which file and node the link points at, or why it cannot be used.
- A preview image, when your team has a Figma token in Team settings. Grails draws it when you paste the link, and you see it in the editor before saving. It does not follow the file: Refresh preview draws it again, and Generate preview draws one for a block that has none. Figma limits how often a token can draw, so nothing else draws: not opening the block, not saving the page.
- On a desktop, View live opens it inside the page, as it is in Figma right now, and Open in Figma opens the file. On a phone the block shows its name, its caption and the preview.
- The live view uses your own Figma account. You see it if you can open the file in Figma, or if the file is shared with anyone who has the link; otherwise Figma says so inside the frame. The first time, your browser may ask to let Figma use its cookies on this site.
- Design files only: not FigJam, Slides, prototypes or links to a branch. The link must point at a frame or a component, not at the whole file.
- A file with a password cannot be shown live.
- The preview counts against your team’s storage, as an uploaded image does. Its alternative text is optional: when it is empty, readers hear the caption.
Related — pointing at other entities, and saying why
Use a Related block to connect this entity to others: a verb, the other entity, and — if it
helps a reader — the reason. “Replaces ButtonLegacy, because it merges the three old variants.”
There can be only one Related block per entity. Once it exists, the block menu stops offering it; everything goes as rows inside the one block.
The verbs are a closed list: relates to · see also · pairs with · excludes · alternative to · replaces · refines · same as. Two you will not find there are composes and depends on — Grails already knows those from Figma, and letting you write them by hand would produce two answers to the same question with nothing to say which is current.
The reason is optional, and leaving it empty is a real choice. A relation with no reason still says something useful. A reason written to fill the field — “because yes” — is worse than none, because it takes the place where somebody would look for a real one.
Naming an entity inside a sentence is not a relation. Writing “do not use @Background/Red
on interactive surfaces” in a Text block is a mention: it keeps your sentence, with its “do
not”. A relation keeps only the pair, so the same thing stored as a relation would read as
“this relates to Background/Red” — the opposite of what you wrote. Mention in prose; relate when
you mean to assert the connection itself.
What you get back
Relations are stored as connections, not as text, so the entity on the other side knows about it too. Open that one and your relation appears under Referenced by — read-only there, because it belongs to whoever wrote it. That reverse view is the reason this is not simply a paragraph.
⚠️ Two behaviours that surprise people:
- Deleting an entity deletes its relations, on both sides, and there is no trash for them. Unlike a documentation block on a synced component, nothing brings them back.
- A component deleted in Figma that comes back recovers its documentation but NOT its declared relations. It is consistent — a relation is a statement about a pair, and while one side did not exist there was nothing to state — but it reads like a bug the first time.
Some kinds of entity can be pointed at before they have a page of their own to open. Those show with their name and colour and are simply not clickable yet.
Editing a Block
Blocks are edited in Docs, on the page of the entity, once you press Edit in the bar at the bottom. The documentation drawer does not edit.
Hover a block and its two controls appear in the top-right corner of that block: edit and delete. The block itself picks up a faint tint at the same moment, and that tint is the answer to a question the buttons alone left open — can this be edited at all? A viewer sees the same blocks with neither the tint nor the buttons, so nobody has to find out by trying.
The edit trigger is the button, not the block. Clicking anywhere inside a block used to open its editor, which made ordinary reading hazardous: selecting a line to copy it, or clicking a link in a rule, dropped you into edit mode. Text inside a block is now selectable and links are clickable, the way they are anywhere else on the page.
Editing does not put the block in a box. A block being edited shows a toolbar above it with the controls of its shape — bold and italic for text, the level for a title, the row and column controls for a table — plus Save and Discard. The block itself stays where it is and keeps looking like part of the page it belongs to, which is the point of writing on the page in the first place.
A block with changes you have not saved is marked: a tinted background, a coloured rail down its left edge, and an Unsaved changes label in its toolbar. It stays marked even after you click somewhere else, so a block you left half-written is visible before the warning dialog on the way out tells you about it.
Viewers see no controls at all — the buttons appear only for roles that may write.
Saving
Nothing is written until you press Save. Adding a block, rewriting one, reordering them and deleting one all happen in the browser: you can restructure a whole page and commit it in one go.
That is a change from how it used to work. Every edit used to be written the moment you made it, which meant a half-finished thought was already stored — and reordering blocks twice while thinking was three separate versions of the page.
The page tells you when you have unsaved work, and asks before letting you leave it:
- Done, in the bar, asks first. So does a link to another page, and going to another tab of the same page (from a component’s Docs tab to its Anatomy, say).
- Closing or reloading the browser tab asks too.
- The browser’s back and forward buttons do not ask, and the changes are lost. Save before you use them.
Deleting a block follows the same rule: it disappears from the page immediately, and it is only removed for real when you save. Until then, leaving without saving brings it back.
How Documentation is Authored
Write it directly in Grails, block by block. Each shape has its own editor: a rule picks its level from a dropdown, a use case marks whether it is recommended or discouraged and points at a real alternative component.
Most shapes open their editor in a side panel. Text, titles and tables are edited in place, on the page itself, because what you are judging is how they sit there: the size of a heading against its neighbours, the width of a column against the page. Neither can be judged in a 500px panel and then applied somewhere else.
Agents can also write documentation through the API. Every shape is discoverable there — including what it is for, when not to use it, and a valid example — so an agent picks the same shape a person would.
Permission Notes
| Action | Roles | Notes |
|---|---|---|
| Read Documentation | Admin, Editor, Viewer | All roles can open and read the documentation drawer, and go from it to the entity’s page with Open in Docs. |
| Edit Documentation | Admin, Editor | Only Admins and Editors can update the documentation content, and they do it in Docs: Edit in the page’s bar, or Edit in Docs from an empty drawer. |