Typography
Five questions every design system answers about typography. These are Dense data’s answers, and each one points back to the reasons that chose it.
View all 28 typography tokens ↓The reasons this scheme answers from
- R1Content and dataNumbers and records, a lot
- R2Tasks and flowsScan and compare, constantly
- R3People and work contextDaily experts, AA
Question 1
Which text roles does it need?
- Core: heading, body, label
- Core and data (chosen)
- Core and editorial display
- Core and expressive display
Why Dense data picks it: A data role keeps numbers in aligned columns.
becauseR1R2
Question 2
How many steps does the type scale take?
- Only the steps the screens need (chosen)The scale keeps the few sizes the screens use, and nothing in between.
- One step per kind of textOne size each for caption, body, heading, title and display.
- Fine steps, so pages can set their own rhythmMany close sizes, so a page can tune its hierarchy and pace.
Why Dense data picks it: A screen full of records stays calm with only the sizes it needs.
becauseR1
Question 3
How are sizes and line heights defined?
- A ratio, line heights on the grid (chosen)
- A ratio, line heights in proportion
- Fixed steps
Why Dense data picks it: Lines stay on the grid so rows align, and grow with the user's text size.
becauseR2R3
- A ratio, line heights on the grid
- from font.family
- from font.size
- from font.line-height
- from font.weight
Decisions point at primitives, so the rule lives in one place.
Question 4
How large is body text?
- Small (chosen)
- Regular
- Large
Why Dense data picks it: Small body text fits more rows on the screen.
becauseR1
- display
- font-family
- → font.family.ibm-plex-sans
- font-size
- → font.size.24
- line-height
- → font.line-height.28
- font-weight
- → font.weight.600
- title
- font-family
- → font.family.ibm-plex-sans
- font-size
- → font.size.20
- line-height
- → font.line-height.24
- font-weight
- → font.weight.600
- heading
- font-family
- → font.family.ibm-plex-sans
- font-size
- → font.size.16
- line-height
- → font.line-height.20
- font-weight
- → font.weight.600
- body
- font-family
- → font.family.ibm-plex-sans
- font-size
- → font.size.14
- line-height
- → font.line-height.20
- font-weight
- → font.weight.400
- label
- font-family
- → font.family.ibm-plex-sans
- font-size
- → font.size.12
- line-height
- → font.line-height.16
- font-weight
- → font.weight.500
- caption
- font-family
- → font.family.ibm-plex-sans
- font-size
- → font.size.12
- line-height
- → font.line-height.16
- font-weight
- → font.weight.400
- data
- font-family
- → font.family.ibm-plex-mono
- font-size
- → font.size.13
- line-height
- → font.line-height.16
- font-weight
- → font.weight.400
Question 5
Where does type do the most work?
- Tables and inputs (chosen)
- Articles and long text
- Forms and labels
- Headlines and hero
Why Dense data picks it: Most text sits in table cells and inputs.
becauseR1
- button · 2 keys
- input · 1 keys
- badge · 1 keys
- table · 1 keys
When to use
- Page titleUse: type.title. Not: type.display. Titles stay small so the table starts higher on the screen.
- A number in a tableUse: type.data. Not: type.body. Mono digits line up in columns, so values compare at a glance.
- Paragraph or help textUse: type.body. Not: type.label. Help text is read in passing; body size keeps it quick.
- Field label or column headerUse: type.label. Not: type.heading. Headers repeat on every column; a heavy style would compete with the data.
All typography tokens
28 tokens · each decision and the primitive it points to
- font.family · 2
font.family.ibm-plex-sans"IBM Plex Sans", system-ui, sans-seriffont.family.ibm-plex-mono"IBM Plex Mono", ui-monospace, monospace - font.size · 6
font.size.241.5rem · 24pxfont.size.201.25rem · 20pxfont.size.161rem · 16pxfont.size.140.875rem · 14pxfont.size.120.75rem · 12pxfont.size.130.8125rem · 13px - font.line-height · 4
font.line-height.281.75rem · 28pxfont.line-height.241.5rem · 24pxfont.line-height.201.25rem · 20pxfont.line-height.161rem · 16px - font.weight · 3
font.weight.600600font.weight.400400font.weight.500500 - Decisions · 28
type.display.font-family{font.family.ibm-plex-sans}type.display.font-size{font.size.24}type.display.line-height{font.line-height.28}type.display.font-weight{font.weight.600}type.title.font-family{font.family.ibm-plex-sans}type.title.font-size{font.size.20}type.title.line-height{font.line-height.24}type.title.font-weight{font.weight.600}type.heading.font-family{font.family.ibm-plex-sans}type.heading.font-size{font.size.16}type.heading.line-height{font.line-height.20}type.heading.font-weight{font.weight.600}type.body.font-family{font.family.ibm-plex-sans}type.body.font-size{font.size.14}type.body.line-height{font.line-height.20}type.body.font-weight{font.weight.400}type.label.font-family{font.family.ibm-plex-sans}type.label.font-size{font.size.12}type.label.line-height{font.line-height.16}type.label.font-weight{font.weight.500}type.caption.font-family{font.family.ibm-plex-sans}type.caption.font-size{font.size.12}type.caption.line-height{font.line-height.16}type.caption.font-weight{font.weight.400}type.data.font-family{font.family.ibm-plex-mono}type.data.font-size{font.size.13}type.data.line-height{font.line-height.16}type.data.font-weight{font.weight.400}
Decisions reference primitives, so changing one primitive updates every decision and component that uses it.
Typography in Dense data: small. Small body text fits more rows on the screen. Most text sits in table cells and inputs.