Docs layout
Four layers, one job each
| Section | py-4 | Vertical rhythm only |
| Container | max 1200, px-4 | Width only, centred |
| Row | 12 columns, gap 32 | Columns only |
| Cell | span 8 or 4 | Where content goes |
A section knows nothing about width; a container knows nothing about vertical space. Content inside a cell flows to fill it. No block of text spans more than 8 of the 12 columns; the other 4 are for things beside it.
From ntb.no
.content-module 32 px above, 80 below. .grid-container 1200 px, 15 px side padding. .grid-x −15 px margin, .cell 15 px padding: content lands on the container’s padding line.
One unit: half a gutter
Every box owns half a gutter, 16 px, on each side. Whether that half is inside or outside the box depends on whether the box has a visible edge: a background, a border or a picture.
| Content next to content | 32 px | 16 + 16 padding |
| Visible edge to its own content | 16 px | Padding |
| Visible edge to its neighbour | 32 px | 16 margin + 16 |
Without a visible edge nobody can see where a box ends, so padding does the whole job. Add a background and the padding becomes the space inside the colour; the space to the neighbours has to come back as margin outside it.
From Carbon
Each column has 16 px padding on both sides, together the 32 px gutter. Boxes either keep their edge on the column line (wide mode) or hang 16 px into the gutter (narrow mode). Type never hangs.
A section with a background
The section’s 16 px padding is now inside the colour, so the text keeps clear of its edges, and 16 px of margin outside keeps it apart from the sections above and below. The container inside is unchanged, so this text lines up with the text outside.
Not a band
Just a section with a background, like ntb.no’s .grey-box: padding inside, margin outside.
Rows of boxes
Cards next to each other keep their edges on the column lines, like ntb.no’s cards (.grid-margin-x): if they hung into the gutter they would touch. Their content is inset by their own 16 px padding.
A single box among text
An example or a code block has a visible edge but sits alone among text, so it hangs half a gutter out on both sides. Its own 16 px padding brings its content back to the column line, in line with the text above.
<Cell span={12} hang>
<Example code={…}>…</Example>
</Cell>Dense tables use a fluid container
A table with many columns gets a section whose container has no max width. It hangs like any box with an edge, so its cell text lines up with the text column at the left. Its intro stays in a text cell.
| Token | Role | NTB light | NTB dark | Default light | Default dark |
|---|---|---|---|---|---|
| surface | The page. | #ffffff | #1c1817 | #ffffff | #0a0a0a |
| surface-raised | Cards and panels on the page. | #ffffff | #241e1c | #ffffff | #171717 |
| band | A full-width band that sets a section apart; the docs sidebar. | #f5f1ef | #2b2422 | #f5f5f5 | #171717 |
| ink | Headings and body text. | #323232 | #f5f1ef | #0a0a0a | #fafafa |
| ink-muted | Secondary text: summaries, captions, metadata. | #6d605b | #b5aaa5 | #666666 | #a3a3a3 |
| line | Card borders, table rules, dividers. | #e6e6e6 | #3b302b | #e5e5e5 | #262626 |
| line-strong | Input underlines and borders that must be seen. | #9a918d | #6d605b | #a3a3a3 | #525252 |
| brand | Brand bands: top bar, newsletter, footer. | #320002 | #320002 | #171717 | #262626 |
| on-brand | Text on brand bands. | #ffe2da | #ffe2da | #fafafa | #fafafa |
| action | Primary buttons. | #320002 | #ffe2da | #171717 | #fafafa |
| action-hover | Primary buttons, hovered. | #5c0a0c | #ffc9ba | #404040 | #d4d4d4 |
| on-action | Text on primary buttons. | #ffffff | #320002 | #fafafa | #171717 |
| neutral-action | The neutral (secondary) button. | #323232 | #f5f1ef | #e5e5e5 | #404040 |
| on-neutral-action | Text on the neutral button. | #ffffff | #1c1817 | #171717 | #fafafa |
| accent | Lava, as decoration: logo, stripe, active markers. Never body text. | #ff5120 | #ff5120 | #737373 | #a3a3a3 |
| accent-text | Lava for small text that must be readable: eyebrow labels. | #c2380e | #ff7a52 | #525252 | #d4d4d4 |
| accent-soft | Tinted tiles behind icons. | rgb(255 81 32 / 0.08) | rgb(255 81 32 / 0.16) | rgb(0 0 0 / 0.05) | rgb(255 255 255 / 0.08) |
| link-underline | The underline under text links. | #320002 | #ff5120 | #a3a3a3 | #737373 |
| focus | Keyboard focus outline. | #ff5120 | #ff7a52 | #737373 | #a3a3a3 |
| info | Information text and markers. | #1d5fb8 | #8fb8f2 | #1d5fb8 | #8fb8f2 |
| info-soft | Information background. | #e8f0fb | #1a2433 | #e8f0fb | #1a2433 |
| warning | Caution text and markers. | #8a5a00 | #f2c46b | #8a5a00 | #f2c46b |
| warning-soft | Caution background. | #fbf1dc | #2e2412 | #fbf1dc | #2e2412 |
| success | Positive text and markers. | #0a7350 | #6fd3aa | #0a7350 | #6fd3aa |
| success-soft | Positive background. | #e2f4ec | #12261e | #e2f4ec | #12261e |
| danger | Error and "don’t" text and markers. | #b3261e | #ff8a80 | #b3261e | #ff8a80 |
| danger-soft | Error background. | #fbe9e7 | #3a1614 | #fbe9e7 | #3a1614 |
| cat-1 | Category 1 (blue) in diagrams and legends: markers and text. | #1d5fb8 | #8fb8f2 | #1d5fb8 | #8fb8f2 |
| cat-1-soft | Category 1 background. | #e8f0fb | #1a2433 | #e8f0fb | #1a2433 |
| cat-2 | Category 2 (violet). | #6b3fc4 | #c3a6f5 | #6b3fc4 | #c3a6f5 |
| cat-2-soft | Category 2 background. | #f0eafb | #241a33 | #f0eafb | #241a33 |
| cat-3 | Category 3 (amber). | #8a5a00 | #f2c46b | #8a5a00 | #f2c46b |
| cat-3-soft | Category 3 background. | #fbf1dc | #2e2412 | #fbf1dc | #2e2412 |
| cat-4 | Category 4 (green). | #0a7350 | #6fd3aa | #0a7350 | #6fd3aa |
| cat-4-soft | Category 4 background. | #e2f4ec | #12261e | #e2f4ec | #12261e |
Image grids too
Pictures get more useful with width, so a grid of them gets a fluid container as well. The pictures have visible edges, so the grid hangs: its outer edges line up with the table’s.
What never gets wider
A paragraph, a list, a heading, a short table of a few columns, a callout. If it is mostly words, it stays in 8 columns, and the other 4 are for something beside it.