Skip to main content

Custom fonts

How to load and apply a custom font through the Abyss theming system.

github
View source code
import { createTheme } from '@uhg-abyss/web/tools/theme';
import { Global, css, ThemeProvider } from '@uhg-abyss/web/ui/ThemeProvider';

Applying a custom font involves two steps: loading the font face into the browser, and overriding the font-family tokens in createTheme so Abyss components render your font.

Info

Abyss's font-family token keys are currently named after the brand fonts they ship with (e.g. uhc2020-sans, uhc-serif-headline). Overriding a token with a brand-specific name to apply your custom font is intentional — the token key is cosmetic, and the value is what gets emitted as a CSS variable. More generic token names are planned for a future release.

Loading the font face

Option A — External stylesheet

Pass includeFonts: false to createTheme to suppress the built-in brand @font-face declarations, then load your font via a <link> tag or CSS import. This works with any font source, including Google Fonts and self-hosted CDNs.

<!-- index.html -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet" />
const theme = createTheme('uhc', {
includeFonts: false,
theme: {
fonts: {
'web.core.font-family.uhc2020-sans': 'Roboto',
'web.core.font-family.uhc-serif-headline': 'Roboto',
},
},
});
const App = () => {
return <ThemeProvider theme={theme}>...</ThemeProvider>;
};

Option B — Emotion Global component

If you are self-hosting font files, you can inject @font-face declarations alongside ThemeProvider using the Global component re-exported from @uhg-abyss/web/ui/ThemeProvider. This keeps font injection in JavaScript and avoids style-ordering issues.

const customFontFaces = css`
@font-face {
font-family: 'MyCustomFont';
font-weight: 400;
font-display: swap;
src: url('/fonts/MyCustomFont-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'MyCustomFont';
font-weight: 700;
font-display: swap;
src: url('/fonts/MyCustomFont-Bold.woff2') format('woff2');
}
`;
const theme = createTheme('uhc', {
includeFonts: false,
theme: {
fonts: {
'web.core.font-family.uhc2020-sans': 'MyCustomFont',
'web.core.font-family.uhc-serif-headline': 'MyCustomFont',
},
},
});
const App = () => {
return (
<>
<Global styles={customFontFaces} />
<ThemeProvider theme={theme}>...</ThemeProvider>
</>
);
};

Wiring the font into the token system

Regardless of which loading option you choose, you must override the font-family tokens in createTheme so Abyss components render your font. Which tokens to override depends on your theme.

UHC theme

The UHC theme routes body text and sans-serif headings through web.core.font-family.uhc2020-sans, and serif headings through web.core.font-family.uhc-serif-headline.

TokenApplies to
web.core.font-family.uhc2020-sansBody text and sans-serif headings
web.core.font-family.uhc-serif-headlineSerif headings (omit to keep the brand serif)
const theme = createTheme('uhc', {
theme: {
fonts: {
'web.core.font-family.uhc2020-sans': 'MyCustomFont',
'web.core.font-family.uhc-serif-headline': 'MyCustomFont',
},
},
});

UHC theme with Enterprise Sans

When the enterpriseFont: true flag is set, the UHC theme switches body text and sans-serif headings to web.core.font-family.enterprise-sans-vf instead of uhc2020-sans. Override that token instead.

TokenApplies to
web.core.font-family.enterprise-sans-vfBody text and sans-serif headings
web.core.font-family.uhc-serif-headlineSerif headings (omit to keep the brand serif)
const theme = createTheme('uhc', {
enterpriseFont: true,
theme: {
fonts: {
'web.core.font-family.enterprise-sans-vf': 'MyCustomFont',
'web.core.font-family.uhc-serif-headline': 'MyCustomFont',
},
},
});

Optum theme

The Optum theme routes both body text and all headings through web.core.font-family.enterprise-sans-vf. The serif heading style uses Libre Baskerville, which is set directly on the semantic token rather than the core token layer — to override it, target web.semantic.font-family.h-serif instead.

TokenApplies to
web.core.font-family.enterprise-sans-vfBody text and headings
web.semantic.font-family.h-serifSerif heading style (direct semantic override)
const theme = createTheme('optum', {
theme: {
fonts: {
'web.core.font-family.enterprise-sans-vf': 'MyCustomFont',
'web.semantic.font-family.h-serif': 'MyCustomFont', // omit to keep Libre Baskerville
},
},
});
Table of Contents