Using type

Typesetting in USWDS means understanding the relationship between font family, font size, and line height.

Normalization

Typefaces vary in optical size. This means that at any specific pixel value, an optically small typeface like Source Sans Pro will appear smaller than an optically large typeface like Merriweather. Optical size is a function of internal font metrics and typeface design choices like x-height.

Fonts at native size

optical size of typefaces

USWDS 2 is designed so each size token outputs a consistent optical size regardless of the typeface. This makes our guidance more reliable and our theming more flexible.

Fonts with normalization applied

normalized typefaces

To make different typefaces appear the same size (here called the target size) at each step of the scale (below, we see the output of size token 10), the absolute size of each token’s output varies depending on the font family.

Each supported typeface is normalized to a target value determined by the optical size of common system fonts — specifically Apple’s typeface San Francisco and Google’s typeface Roboto.

For size token 10 (24px) we see the following normalized ouput:
Supported typeface Normalization Final output (px)
Georgia 1.05 25.11
Helvetica 1.01 24.34
Merriweather 0.98 23.42
Open Sans 1.01 24.34
Public Sans 1.0 24.0
Roboto Mono 0.95 22.86
Source Sans Pro 1.06 25.55
System fonts 1.0 24.0
Tahoma 1.0 23.93
Verdana 0.99 23.87

Rem-based font sizing

In USWDS, the final font size is output not in pixels but in rem (a multiple of the page’s root font size). If you have $theme-respect-user-font-size set to true in your theme settings, the root font size is set to 100% and typescale is calculated based on 16px. If $theme-respect-user-font-size set to false, the root font size is set to the value of $theme-root-font-size and typescale is calculated based on that root.

Since both the rem and absolute px values change depending on the theme settings and the typeface, our documentation displays only the px value of the target.

Normalization and line height

USWDS has six target line heights in its line-height token system. These targets are unitless numbers, multipliers of the font size of the affected text. For example, if the target line height were 2 in text with a target font size of 16px, the final line height would be the target line height * target font size or 2 * 16px or 32px.

Since we use normalization on font sizing, we must also normalize line height to hit the target line height:

For size token 10 (24px) and line-height token 3 (1.35 / 32.4px) we see the following normalized ouput:
Supported typeface Normalization Final size (px) Final line height Final line height (px)
Georgia 1.05 25.11 1.29 32.4
Helvetica 1.01 24.34 1.33 32.4
Merriweather 0.98 23.42 1.38 32.4
Open Sans 1.01 24.34 1.33 32.4
Public Sans 1.0 24.0 1.35 32.4
Roboto Mono 0.95 22.86 1.42 32.4
Source Sans Pro 1.06 25.55 1.27 32.4
System fonts 1.0 24.0 1.35 32.4
Tahoma 1.0 23.93 1.35 32.4
Verdana 0.99 23.87 1.36 32.4

Typesetting with tokens

USWDS uses functions, mixins, and utility classes to style its components with design tokens. Because we use normalized values, as described above, font size and line height functions, mixins, and utility classes differ from many others in the system by requiring two tokens: a family token and either a size or a line-height token.

The individual design token sections go into this in more detail, but here’s a summary:

Font family

Token Function Mixin Utility class
family family(family) u-font-family(family) .font-family-family
'body' family('body') u-font-family('body') .font-family-body
'sans' family('sans') u-font-family('sans') .font-family-sans

Font size

Token Function Mixin Utility class
family, size size(family, size) u-font-size(family, size) .font-size-family-size
'ui', 'micro' size('ui', 'micro') u-font-size('ui', 'micro')
'sans', 6 size('sans', 6) u-font-size('sans', 6)

Family and size together

Token Function Mixin Utility class
family, size u-font(family, size) .font-family-size
'ui', 'micro' u-font('ui', 'micro') .font-ui-micro
'sans', 6 u-font('sans', 6) .font-sans-6

Line height

Token Function Mixin Utility class
family,
line-height
line-height(family,
line-height)
u-line-height(family,
line-height)
.line-height-family-line-height
'ui', 1 line-height('ui', 1) u-line-height('ui', 1) line-height-ui-1
'sans', 3 line-height('sans', 3) u-line-height('sans', 3) .line-height-sans-3

Family, size, and line height together

The typeset() mixin outlined below accepts the tokens listed as well as a special null value. If either of the three properties get null instead of a token, the system will use a default value from $uswds-theme-typography: either $theme-body-font-family, $theme-body-font-size, or $theme-body-line-height depending on the property passed the null value.

We use the typeset() mixin on all our components to get the effect of default <body> element styling without having to explicitly style the <body> element.

Token Function Mixin Utility class
family, size, line-height typeset(family, size, line-height)
'ui', 'micro', 1 typeset('ui', 'micro', 1)
'ui', null, 3 typeset('ui', null, 3)
'ui', xs, null typeset('ui', xs)
'ui', null, null typeset('ui')

Example: Settings and typesetting

// in _uswds-theme-typography:

$theme-respect-user-font-size: true;
$theme-font-type-sans:         'public-sans';
$theme-font-role-ui:           $theme-font-sans;
$theme-type-scale-sm:          5;
$theme-body-font-size:         'sm';
$theme-body-line-height:       5;

// in component code:

.usa-component {
  @include typeset('ui');
}

// is the equivalent of:

.usa-component {
  font-family: family('ui');
  font-size: size('ui', $theme-body-font-size);
  line-height: line-height('ui', $theme-body-line-height);
}

// compiles as:

.usa-component {
  font-family: 'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
  font-size: 1rem;
  line-height: 1.62;
}