Open DS

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

displayOpen alerts 142
titleOpen alerts 142
headingOpen alerts 142
bodyOpen alerts 142
labelOpen alerts 142
captionOpen alerts 142
dataOpen alerts 142

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

font family2
font size6
font line-height4
font weight3

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 · 2font.family.ibm-plex-sans"IBM Plex Sans", system-ui, sans-seriffont.family.ibm-plex-mono"IBM Plex Mono", ui-monospace, monospace
  • font.size · 6font.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 · 4font.line-height.281.75rem · 28pxfont.line-height.241.5rem · 24pxfont.line-height.201.25rem · 20pxfont.line-height.161rem · 16px
  • font.weight · 3font.weight.600600font.weight.400400font.weight.500500
  • Decisions · 28type.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.