{"id":22488918,"url":"https://github.com/unjs/unifont","last_synced_at":"2026-02-14T01:06:25.307Z","repository":{"id":257812627,"uuid":"792235421","full_name":"unjs/unifont","owner":"unjs","description":"Framework agnostic tools for accessing data from font CDNs and providers","archived":false,"fork":false,"pushed_at":"2026-02-11T16:41:10.000Z","size":1863,"stargazers_count":260,"open_issues_count":9,"forks_count":14,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-02-12T01:12:42.499Z","etag":null,"topics":["font","performance"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["danielroe"]}},"created_at":"2024-04-26T08:50:04.000Z","updated_at":"2026-02-11T16:41:15.000Z","dependencies_parsed_at":"2024-10-06T16:43:12.140Z","dependency_job_id":"c2151f29-2755-4b77-ac30-9f43c6137d08","html_url":"https://github.com/unjs/unifont","commit_stats":null,"previous_names":["danielroe/unifont"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/unjs/unifont","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unjs%2Funifont","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unjs%2Funifont/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unjs%2Funifont/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unjs%2Funifont/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unjs","download_url":"https://codeload.github.com/unjs/unifont/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unjs%2Funifont/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29423536,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T22:20:51.549Z","status":"ssl_error","status_checked_at":"2026-02-13T22:20:49.838Z","response_time":78,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["font","performance"],"created_at":"2024-12-06T17:18:55.490Z","updated_at":"2026-02-14T01:06:25.300Z","avatar_url":"https://github.com/unjs.png","language":"TypeScript","funding_links":["https://github.com/sponsors/danielroe"],"categories":["TypeScript"],"sub_categories":[],"readme":"# unifont\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![Github Actions][github-actions-src]][github-actions-href]\n[![Codecov][codecov-src]][codecov-href]\n\n\u003e Framework agnostic tools for accessing data from font CDNs and providers.\n\n## Installation\n\nUsing npm:\n\n```\nnpm i unifont\n```\n\nUsing pnpm:\n\n```\npnpm add unifont\n```\n\nUsing yarn:\n\n```\nyarn add unifont\n```\n\n## Getting started\n\nThis package is ESM-only.\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst availableFonts = await unifont.listFonts()\nconst { fonts } = await unifont.resolveFont('Poppins')\n```\n\n## Built-in providers\n\nThe following providers are built-in but you can build [custom providers](#building-your-own-provider) too.\n\n### Adobe\n\nA provider for [Adobe Fonts](https://fonts.adobe.com/).\n\n```js\nimport { providers } from 'unifont'\n\nproviders.adobe({ /* options */ })\n```\n\n#### Options\n\n##### `id`\n\n- Type: `string | string[]`\n- Required\n\n```js\nimport { providers } from 'unifont'\n\nproviders.adobe({ id: 'your-id' })\nproviders.adobe({ id: ['foo', 'bar'] })\n```\n\nIt is recommended to load these IDs as environment variables.\n\n### Bunny\n\nA provider for [Bunny Fonts](https://fonts.bunny.net/).\n\n```js\nimport { providers } from 'unifont'\n\nproviders.bunny()\n```\n\n### Fontshare\n\nA provider for [Fontshare](https://www.fontshare.com/).\n\n```js\nimport { providers } from 'unifont'\n\nproviders.fontshare()\n```\n\n### Fontsource\n\nA provider for [Fontsource](https://fontsource.org/).\n\n```js\nimport { providers } from 'unifont'\n\nproviders.fontsource()\n```\n\nIt uses the API, not installed NPM packages (see [PR #189](https://github.com/unjs/unifont/pull/189)).\n\n### Google\n\nA provider for [Google Fonts](https://fonts.google.com/).\n\n```js\nimport { providers } from 'unifont'\n\nproviders.google()\n```\n\n#### Options\n\n##### `experimental.variableAxis`\n\n- Type: `{ [fontFamily: string]: Partial\u003cRecord\u003cVariableAxis, ([string, string] | string)[]\u003e\u003e }`\n\nAllows setting variable axis configuration on a per-font basis:\n\n```js\nimport { providers } from 'unifont'\n\nproviders.google({\n  experimental: {\n    variableAxis: {\n      Poppins: {\n        slnt: [['-15', '0']],\n        CASL: [['0', '1']],\n        CRSV: ['1'],\n        MONO: [['0', '1']],\n      },\n    },\n  },\n})\n```\n\nOverriden by the `experimental.variableAxis` family option.\n\n##### `experimental.glyphs`\n\n- Type: `{ [fontFamily: string]: string[] }`\n\nAllows specifying a list of glyphs to be included in the font for each font family. This can reduce the size of the font file:\n\n```js\nimport { providers } from 'unifont'\n\nproviders.google({\n  experimental: {\n    glyphs: {\n      Poppins: ['Hello', 'World']\n    },\n  },\n})\n```\n\nOverriden by the `experimental.glyphs` family option.\n\n#### Family options\n\n##### `experimental.variableAxis`\n\n- Type: `Partial\u003cRecord\u003cVariableAxis, ([string, string] | string)[]\u003e\u003e`\n\nAllows setting variable axis configuration on a per-font basis:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  options: {\n    google: {\n      experimental: {\n        variableAxis: {\n          slnt: [['-15', '0']],\n          CASL: [['0', '1']],\n          CRSV: ['1'],\n          MONO: [['0', '1']],\n        },\n      },\n    },\n  },\n})\n```\n\n##### `experimental.glyphs`\n\n- Type: `string[]`\n\nAllows specifying a list of glyphs to be included in the font for each font family. This can reduce the size of the font file:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  options: {\n    google: {\n      experimental: {\n        glyphs: ['Hello', 'World'],\n      },\n    },\n  },\n})\n```\n\n### Google icons\n\nA provider for [Google Icons](https://fonts.google.com/icons).\n\n```js\nimport { providers } from 'unifont'\n\nproviders.googleicons()\n```\n\n#### Options\n\n##### `experimental.glyphs`\n\n- Type: `{ [fontFamily: string]: string[] }`\n\nAllows specifying a list of glyphs to be included in the font for each font family. This can reduce the size of the font file:\n\n```js\nimport { providers } from 'unifont'\n\nproviders.googleicons({\n  experimental: {\n    glyphs: {\n      'Material Symbols Outlined': ['arrow_right', 'favorite', 'arrow_drop_down']\n    },\n  },\n})\n```\n\nOnly available when resolving the new `Material Symbols` icons. Overriden by the `experimental.glyphs` family option.\n\n#### Family options\n\n##### `experimental.glyphs`\n\n- Type: `string[]`\n\nAllows specifying a list of glyphs to be included in the font for each font family. This can reduce the size of the font file:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.googleicons(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  options: {\n    googleicons: {\n      experimental: {\n        'Material Symbols Outlined': ['arrow_right', 'favorite', 'arrow_drop_down']\n      },\n    },\n  },\n})\n```\n\nOnly available when resolving the new `Material Symbols` icons.\n\n## `Unifont`\n\nUse `createUnifont()` to create a `Unifont` instance. It requires an array of font providers at this first parameter:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n```\n\n### Options\n\n`createUnifont()` accepts options as its 2nd parameter.\n\n#### `storage`\n\n- `Type`: `Storage`\n\nAllows caching the results of font APIs to avoid unnecessary hits to them. Uses a memory cache by default.\n\nThis storage type is compatible with [`unstorage`](https://unstorage.unjs.io.):\n\n```ts\nimport { createUnifont, providers } from 'unifont'\nimport { createStorage } from 'unstorage'\nimport fsDriver from 'unstorage/drivers/fs-lite'\n\nconst storage = createStorage({\n  driver: fsDriver({ base: 'node_modules/.cache/unifont' }),\n})\n\nconst unifont = await createUnifont([\n  providers.google()\n], { storage })\n\n// cached data is stored in `node_modules/.cache/unifont`\nawait unifont.resolveFont('Poppins')\n```\n\n#### `throwOnError`\n\n- Type: `boolean`\n\nAllows throwing on error if a font provider:\n\n- Fails to initialize\n- Fails while calling `resolveFont()`\n- Fails while calling `listFonts()`\n\nIf set to `false` (default), an error will be logged to the console instead:\n\n```ts\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google()\n], { throwOnError: true })\n```\n\n### Methods\n\n#### `resolveFont()`\n\n- Type: `(fontFamily: string, options?: Partial\u003cResolveFontOptions\u003e, providers?: T[]) =\u003e Promise\u003cResolveFontResult \u0026 { provider?: T }\u003e`\n\nRetrieves font face data from available providers:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n  providers.fontsource(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins')\n```\n\nIt loops through all providers and returns the result of the first provider that can return some data.\n\n##### Options\n\nIt accepts options as the 2nd parameter. Each provider chooses to support them or not.\n\n###### `weights`\n\n- Type: `string[]`\n- Default: `['400']`\n\nSpecifies what weights to retrieve. Variable weights must me in the format `\u003cmin\u003e \u003cmax\u003e`:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  weights: ['300', '500 900']\n})\n```\n\n###### `styles`\n\n- Type: `('normal' | 'italic' | 'oblique')[]`\n- Default: `['normal', 'italic']`\n\nSpecifies what styles to retrieve:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  styles: ['normal']\n})\n```\n\n###### `subsets`\n\n- Type: `string[]`\n- Default: `['cyrillic-ext', 'cyrillic', 'greek-ext', 'greek', 'vietnamese', 'latin-ext', 'latin']`\n\nSpecifies what subsets to retrieve:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  subsets: ['latin']\n})\n```\n\n###### `options`\n\n- Type: `{ [key: string]?: Record\u003cstring, any\u003e }`\n\nA provider can define options to provide on a font family basis. Types will be automatically inferred:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  options: {\n    google: {\n      experimental: {\n        glyphs: ['Hello', 'World']\n      }\n    }\n  },\n})\n```\n\n###### `formats`\n\n- Type: `('woff2' | 'woff' | 'otf' | 'ttf' | 'eot')[]`\n- Default: `['woff2']`\n\nSpecifies what font formats to retrieve:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {\n  formats: ['woff2', 'woff2']\n})\n```\n\n##### Providers\n\n- Type: `string[]`\n\nBy default it uses all the providers provided to `createUnifont()`. However you can restrict usage to only a subset:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n  providers.fontsource(),\n])\n\nconst { fonts } = await unifont.resolveFont('Poppins', {}, ['google'])\n```\n\n#### `listFonts()`\n\n- Type: `(providers?: T[]) =\u003e Promise\u003cstring[] | undefined\u003e`\n\nRetrieves font names available for all providers:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n])\n\nconst availableFonts = await unifont.listFont()\n```\n\nIt may return `undefined` if no provider is able to return names.\n\n##### Providers\n\n- Type: `string[]`\n\nBy default it uses all the providers provided to `createUnifont()`. However you can restrict usage to only a subset:\n\n```js\nimport { createUnifont, providers } from 'unifont'\n\nconst unifont = await createUnifont([\n  providers.google(),\n  providers.fontsource(),\n])\n\nconst availableFonts = await unifont.listFont(['google'])\n```\n\n## Building your own provider\n\n### Defining a provider\n\nTo build your own font provider, use the `defineFontProvider()` helper:\n\n```ts\nimport { defineFontProvider } from 'unifont'\n\nexport const myProvider = defineFontProvider(/* ... */)\n```\n\nIt accepts a unique name as a first argument and a callback function as 2nd argument:\n\n```ts\nimport { defineFontProvider } from 'unifont'\n\nexport const myProvider = defineFontProvider('my-provider', async (options, ctx) =\u003e {\n  // ...\n})\n```\n\nIf you use options, you can simply annotate it:\n\n```ts\nimport { defineFontProvider } from 'unifont'\n\nexport interface MyProviderOptions {\n  foo?: string\n}\n\nexport const myProvider = defineFontProvider('my-provider', async (options: MyProviderOptions, ctx) =\u003e {\n  // ...\n})\n```\n\nThe context (`ctx`) gives access to the [`storage`](#storage), allowing you to cache results. We'll see how below.\n\n### Initialization\n\nThe callback runs when a `Unifont` instance is created. It is used for initialization logic, such as fetching the list of available fonts:\n\n```ts\nimport { defineFontProvider } from 'unifont'\n\nexport const myProvider = defineFontProvider('my-provider', async (options, ctx) =\u003e {\n  const fonts: { name: string, cssUrl: string }[] = await ctx.storage.getItem('my-provider:meta.json', () =\u003e fetch('https://api.example.com/fonts.json').then(res =\u003e res.json()))\n\n  // ...\n})\n```\n\nYou can now use this data in the methods.\n\n### `listFonts()`\n\nWhile optional, it's easy to implement this method now that we have the full list:\n\n```ts\nimport { defineFontProvider } from 'unifont'\n\nexport const myProvider = defineFontProvider('my-provider', async (options, ctx) =\u003e {\n  const fonts: { name: string, cssUrl: string }[] = [/* ... */]\n\n  return {\n    listFonts() {\n      return fonts.map(font =\u003e font.name)\n    }\n    // ...\n  }\n})\n```\n\n### `resolveFont()`\n\nThis is where most of the logic lies. It depends a lot on how the provider works, and often involves parsing CSS files. Have a look at the implementation of built-in providers for inspiration!\n\n```ts\nimport { hash } from 'ohash'\nimport { defineFontProvider } from 'unifont'\n\nexport const myProvider = defineFontProvider('my-provider', async (options, ctx) =\u003e {\n  const fonts: { name: string, cssUrl: string }[] = [/* ... */]\n\n  return {\n    // ...\n    async resolveFont(fontFamily, options) {\n      const font = fonts.find(font =\u003e font.name === fontFamily)\n      if (!font) {\n        return\n      }\n\n      return {\n        fonts: await ctx.storage.getItem(`my-provider:${fontFamily}-${hash(options)}-data.json`, async () =\u003e {\n          // Fetch an API, extract CSS...\n          return [/* ... */]\n        })\n      }\n    }\n  }\n})\n```\n\nIf you use family options, you can override the type of `options` and it will be inferred:\n\n```ts\nimport type { ResolveFontOptions } from 'unifont'\nimport { hash } from 'ohash'\nimport { defineFontProvider } from 'unifont'\n\nexport interface MyProviderFamilyOptions {\n  foo?: string\n}\n\nexport const myProvider = defineFontProvider('my-provider', async (options, ctx) =\u003e {\n  // ...\n\n  return {\n    // ...\n    async resolveFont(fontFamily, options: ResolveFontOptions\u003cMyProviderFamilyOptions\u003e) {\n      // ...\n    }\n  }\n})\n```\n\n## 💻 Development\n\n- Clone this repository\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev`\n\n## License\n\nMade with ❤️\n\nPublished under [MIT License](./LICENCE).\n\n\u003c!-- Badges --\u003e\n\n[npm-version-src]: https://img.shields.io/npm/v/unifont?style=flat-square\n[npm-version-href]: https://npmjs.com/package/unifont\n[npm-downloads-src]: https://img.shields.io/npm/dm/unifont?style=flat-square\n[npm-downloads-href]: https://npm.chart.dev/unifont\n[github-actions-src]: https://img.shields.io/github/actions/workflow/status/unjs/unifont/ci.yml?branch=main\u0026style=flat-square\n[github-actions-href]: https://github.com/unjs/unifont/actions?query=workflow%3Aci\n[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/unifont/main?style=flat-square\n[codecov-href]: https://codecov.io/gh/unjs/unifont\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funjs%2Funifont","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funjs%2Funifont","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funjs%2Funifont/lists"}