These pages document the typography in the Beta. If you are coming from Latest, or from the earlier beta, the token names have changed, and so has the way line height and weight work, so please start with coming from an earlier version.
Here is one line of interface text, with every property set by a token:
.label {
font-family: var(--eds-font-family-ui);
font-size: var(--eds-typography-label-md-font-size);
line-height: var(--eds-typography-label-md-line-height);
font-weight: var(--eds-font-weight-normal);
}
A step is a font size and the line height that goes with it. Set the line height wherever you set the font size, because text without its own line height inherits one from its parent.
Three roles
Every piece of text takes one of three roles. Two typefaces cover them: Equinor for headers, and Inter for everything else.
| Role | Typeface | Steps | Weights | Use it for |
|---|---|---|---|---|
typography.header | Equinor | xs to 4xl | medium | titles: the headings of pages and sections |
typography.label | Inter | xs to 5xl | normal, medium, bold | single-line functional text: buttons, navigation, table cells, form labels, captions |
typography.body | Inter | sm to 3xl | normal, bold | running text that wraps: paragraphs and descriptions |
Choosing a role
Ask what the text is, and whether it wraps:
- It is a title:
header. The heading of a page or a section. - It stays on one line:
label. A button, a menu item, a table cell, a form label. - It wraps, or could:
body. A paragraph, a description, a message that runs to sentences.
The size of the text does not change its role. A key figure, such as the headline value "312 bar"
on a dashboard, is label because it is a value on one line, even when it is set larger than the
page title.
body uses the same font sizes as label, with a line height of at least one and a half times the
font size, so the eye can find the next line in a block of text.
The steps
Each role has its own range of steps. Comfortable values, as font size / line height in px:
| Step | header | label | body |
|---|---|---|---|
xs | 12 / 16 | 10 / 16 | – |
sm | 14 / 20 | 12 / 16 | 12 / 20 |
md | 16 / 20 | 14 / 20 | 14 / 24 |
lg | 18 / 24 | 16 / 24 | 16 / 28 |
xl | 21 / 28 | 18 / 24 | 18 / 28 |
2xl | 24 / 32 | 21 / 28 | 21 / 32 |
3xl | 28 / 36 | 24 / 32 | 24 / 36 |
4xl | 32 / 40 | 28 / 32 | – |
5xl | – | 32 / 36 | – |
A dash means the role has no such step. The values change with density, and
the token reference lists them in all three densities. In running
text we shorten the names, so typography.label.md becomes label.md.
Equinor's scale runs one step ahead of Inter's, so a header is larger than the label with the same step name. The type scale shows the two side by side.
Groups of steps
Within each role, the steps fall into groups by where the text sits. Components use the smaller steps, and the page around the components uses the larger ones:
| Role | Group | Steps | Use |
|---|---|---|---|
header | Page title | 4xl | the h1, which names the page |
| Sections | 3xl, 2xl | h2 and h3 | |
| Subsections | xl, lg, md | h4, h5 and h6 | |
| Headings with no default element | sm, xs | page-chrome headings that must look smaller than an h6 | |
label | Inside components | xs to lg | single-line component text, with md as the default |
| Page layout | xl to 5xl | top-level navigation, the app name, and key figures | |
body | Inside components | sm, md | helper text under a field, and text that wraps inside a component |
| Page | lg, xl | running text, and the ingress: the introduction under the page title | |
| Page layout | 2xl, 3xl | intro text on front pages, pull quotes, and text read from a distance |
The decision table gives the step for each use, and
heading levels gives the header step for h1 to h6.
Weight
Weight is set separately from size. A text style combines a step with one of three weights:
| Token | CSS custom property | Value | Use it for |
|---|---|---|---|
font-weight.normal | --eds-font-weight-normal | 400 | the default for label and body text |
font-weight.medium | --eds-font-weight-medium | 500 | every header, and label text that needs emphasis |
font-weight.bold | --eds-font-weight-bold | 700 | strong emphasis in label and body text, and <strong> and <b> on the web |
Each role has a fixed set of weights, listed in the roles table. On the web,
<em> and <i> set no weight: they keep the weight of the text around them and turn italic.
They all mean the same weight. The token is font-weight.normal, which is what you write in code.
The Figma text styles call it default, as in label/md/default, and Figma's font picker shows the
Inter weight as Regular.
Typefaces
| Token | CSS custom property | Typeface | Used by |
|---|---|---|---|
font-family.header | --eds-font-family-header | Equinor | header |
font-family.ui | --eds-font-family-ui | Inter | label and body |
Loading the fonts
The EDS variable font stylesheet loads both Equinor and Inter:
<link
rel="stylesheet"
href="https://cdn.eds.equinor.com/font/eds-uprights-vf.css"
/>
equinor-font.css does not include InterThe older equinor-font.css stylesheet only includes Equinor. With it alone, every label and
body style, which is most of an interface, falls back to a generic sans-serif without any error.
Density
The data-density attribute resizes the interface. It moves type size and line height together,
along with spacing, so the proportions you designed are kept:
<div data-density="compact">…</div>
Compact takes the size and line height of the next smaller step, and Relaxed the next larger. So a
label.md in Compact is set like a label.sm in Comfortable. Switch the density below and watch
the values change while the token names stay the same:
Comfortable is the default, used where no data-density is set.
Density on the spacing page explains which density to use where, and
how density works explains the rule for type.
Principles
The decisions about size, weight and line height on these pages follow four principles.
Safety through legibility
Our main goal in typography is safety, and we reach it through legibility. A change that makes text harder to read accurately and quickly counts as a regression, even when it improves something else.
Text sets the proportions
We build from our minimal unit, the text, and from there we define the proportions for padding, line height and gaps. Line heights come from the same scale as spacing, so text and layout share one rhythm, and a component's height follows from its text and padding rather than being set on its own.
Values are adjusted by eye
A consistent visual rhythm makes an interface easier to use, so when a value that follows the scales looks wrong on screen, we change the value. The header line heights are one example: they are chosen for how Equinor looks, and most of them sit above the step their font size would give. Header line heights lists them.
Fixed choices and guidance
We keep the options few enough to choose between quickly, and leave room where teams' needs
differ. Some choices are fixed: each role has a set of weights, and a header is always medium.
Others are guidance: the header step for each heading level
is a starting point that a layout can depart from.
Coming from an earlier version
Latest is the version most products use today, with the components and the Figma library in
production. The earlier beta is the beta typography from before these tokens, which used the Figma
Typography component. For developers, Latest is eds-core-react and eds-tokens 2.x, and the
earlier beta is the ui-body tokens.
From Latest
Re-pick each piece of text with the question in choosing a role and
the groups of steps, instead of looking for its old size on the new scale. They
ask what the text does and where it sits, so they give the same answer on every page, whatever the
old layout used. Component text does not always keep its old size either: a field label is 12px in
Latest, and label.md in the Beta.
From the earlier beta
The earlier beta had one Inter role, ui-body, with two line heights per step, and weight, tracking
and baseline trim per step as well. The Beta splits that role in two and moves weight out of the
size tokens:
| Earlier beta | Beta |
|---|---|
--eds-typography-ui-body-{size}-font-size with -line-height-squished, for UI text | --eds-typography-label-{step}-font-size and -line-height |
--eds-typography-ui-body-{size}-font-size with -line-height-default, for prose | --eds-typography-body-{step}-font-size and -line-height |
--eds-typography-header-{size}-font-size and -line-height-* | --eds-typography-header-{step}-font-size and -line-height |
--eds-typography-header-font-family, --eds-typography-ui-body-font-family | --eds-font-family-header, --eds-font-family-ui |
--eds-typography-{family}-{size}-font-weight-normal | --eds-font-weight-normal |
--eds-typography-{family}-{size}-font-weight-bolder | --eds-font-weight-medium, the same weight |
--eds-typography-{family}-{size}-font-weight-lighter | none. The lighter weight is gone, so use --eds-font-weight-normal |
--eds-typography-{family}-{size}-tracking-* | none. Letter spacing is the typeface's own, with no token |
.eds-heading-bold, .eds-heading-light | none. Headers have one weight |
data-density="spacious", or no attribute | no attribute, which gives Comfortable |
data-density="comfortable" | data-density="compact" |
For ui-body, the step names carry over, and the Comfortable sizes are the spacious sizes of the
earlier beta, rounded to whole pixels, up to 5xl. There is no 6xl. Spacing renamed its
densities in the same way, as the warning on the spacing page describes.
Three other things changed that no token mapping shows:
- There is no baseline trim. The earlier beta trimmed multi-line text to the baseline with
text-box. The Beta does not trim: a line of text is as tall as its line height, in Figma and in code. - Weight no longer changes with size. In the earlier beta, each step had its own weights. Now a
role has a fixed set, and a large header uses the same
mediumas a small one. - The Figma Typography component is gone. Text is set with text styles, such as
label/md/default, which you can find with their sizes in the Figma style list.
The first Beta releases (eds-tokens 3.0.0-beta.1 to 3.0.0-beta.7) named the Inter role ui and
had bolder and lighter weights. ui is now label, with the same values, or body for text
that wraps. bolder is now medium, at the same weight, and lighter is removed.
Where to go next
- The type scale: the scales under the names, where line heights come from, and how density maps onto them.
- Using typography: which role and step to use, the header step for each heading level, worked examples, and the mistakes to avoid.
- Token reference: every token and every value, in all three densities.