unifont
  • All fonts Browse or filter the whole catalogue
  • Compare providers One family, every CDN, side by side
  • Documentation Install, providers, custom providers
  • HTTP API The endpoints this site is built on

API reference

Every export, option and signature in one place.

Three runtime exports, one of them a namespace, and the types behind them:

ts

import { createUnifont, defineFontProvider, providers } from 'unifont'
import type { FontFaceData, FontProperties, ResolveFontOptions, ResolveFontResult, Unifont } from 'unifont'

createUnifont()

ts

function createUnifont<T extends [Provider, ...Provider[]]>(
  providers: T,
  options?: UnifontOptions,
): Promise<Unifont<T>>

Providers are tried in order. The first one that knows a family answers.

Awaiting this starts every provider, and some fetch a whole family index to do it. Keep the instance rather than making one per request.

OptionTypeDefault
storage{ getItem, setItem }in memoryCaching
throwOnErrorbooleanfalsesee below
apiBasestring | falsethe hosted proxy in a browser, otherwise unsetBrowser and web containers

By default a provider that fails to start, or throws from any of the three methods, is logged and skipped. Set throwOnError and you get the error instead.

resolveFont()

ts

resolveFont(
  family: string,
  options?: Partial<ResolveFontOptions>,
  providers?: string[]
): Promise<ResolveFontResult & { provider?: string }>

You get back fonts, the @font-face descriptors; fallbacks, the generic families to put after yours in a stack; and the provider that answered.

Options are hints. Ask a provider that only serves woff2 for otf and you'll get woff2.

OptionTypeDefault
weightsstring[]['400']
styles('normal' | 'italic' | 'oblique')[]['normal', 'italic']
subsetsstring[]['cyrillic-ext', 'cyrillic', 'greek-ext', 'greek', 'vietnamese', 'latin-ext', 'latin']
formats('woff2' | 'woff' | 'otf' | 'ttf' | 'eot')[]['woff2']
options{ [provider: string]: Record<string, unknown> }none

A weight range is one string with a space in it: '100 900'. The defaults above are exported as defaultResolveOptions.

Resolving fonts explains what each option does to the answer. What goes in options is up to each provider, and the built-in ones are under Providers.

listFonts()

ts

listFonts(providers?: string[]): Promise<string[] | undefined>

Every family name the providers will list, or undefined if none of them can. npm and adobe never list.

getFontProperties()

ts

getFontProperties(
  family: string,
  providers?: string[]
): Promise<(FontProperties & { provider?: string }) | undefined>

What a family publishes, from the first provider that knows it, and undefined when none of them do.

Two things to watch when you read the result. weights mixes discrete values ('400') with variable ranges ('100 900'). And a missing field means the provider doesn't publish that information, not that there's nothing to publish: formats in particular is what the provider can serve in general, so a format listed there may still be missing for the family you asked about.

Asking only some providers

All three methods take a list of provider names as their last argument. The default is every provider the instance was built with.

ts

const unifont = await createUnifont([providers.google(), providers.bunny()])

await unifont.resolveFont('Poppins', {}, ['bunny'])
await unifont.getFontProperties('Poppins', ['bunny'])
await unifont.listFonts(['bunny'])

FontFaceData

ts

interface FontFaceData {
  src: Array<{ name: string } | { url: string, format?: string, tech?: string }>
  display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional'
  weight?: string | number | [number, number]
  stretch?: string
  style?: string
  unicodeRange?: string[]
  featureSettings?: string
  variationSettings?: string
  metrics?: FontMetrics
  meta?: { priority?: number, subset?: string, init?: RequestInit }
}

A src entry with name is a local font, one with url is remote. meta.subset is the provider's own name for the range. meta.init holds a RequestInit for the few providers whose files need headers.

FontMetrics

ts

interface FontMetrics {
  unitsPerEm: number
  ascent?: number
  descent?: number
  lineGap?: number
  capHeight?: number
  xHeight?: number
  xWidthAvg?: number
}

Values are in font units, using the same vocabulary as @capsizecss/metrics, so they can be used to generate fallback metric overrides (size-adjust, ascent-override, ...) without downloading and parsing the font file.

defineFontProvider()

ts

function defineFontProvider<Name extends string, Options, FamilyOptions>(
  name: Name,
  provider: (options: Options, ctx: ProviderContext) => Awaitable<{
    resolveFont: (family: string, options: ResolveFontOptions<FamilyOptions>) => Awaitable<ResolveFontResult | undefined>
    getFontProperties?: (family: string) => Awaitable<FontProperties | undefined>
    listFonts?: () => Awaitable<string[] | undefined>
  } | undefined>
): (options?: Options) => Provider<Name, FamilyOptions>

resolveFont() is the only method you have to write. Writing a provider covers the rest.