Library / SDK
Pomax/lib-font avatar
Pomax/lib-font

lib-font: a Font object for inspecting OpenType fonts in JavaScript

This library adds a new Font() object to the JavaScript toolbox, similar to new Image() for images

757 stars74 forksJavaScriptMIT

At a glance

What is it?
lib-font adds a new Font() object to the JavaScript toolbox, in the same spirit as new Image(), so a font can be loaded from a URL or a byte buffer and then queried for character support, OpenType tables and variable font axes. It suits anyone who has to reason about font internals in a browser or in Node, and its API documentation is still pending.
Who is it for?
lib-font fits a developer building a font picker, a checker, or a web tool that needs to know what a typeface actually contains rather than what its metadata claims, and it does not fit a project that only needs to load a font for rendering, where a plain @font-face rule is enough.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A Font object for JavaScript, in the spirit of new Image()

lib-font adds a new Font() object to the JavaScript toolbox, similar to new Image() for images. The framing is exact, and it is worth unpacking what it implies.

An Image object has a src property, fires load and error events, and gives you a handle on the decoded resource. A Font object here behaves the same way: you set a source, you attach onload and onerror handlers, and when the load completes you get the parsed font. The difference is that the payload is an OpenType font and the API on the far side is a font inspector rather than a bitmap.

The question the project asks is the one in its own readme: what if you could actually inspect your fonts, in the same context that you actually use those fonts. That is a real gap in browser tooling. The FontFace API in the browser tells you whether a font loaded and which family it belongs to, but it does not tell you whether the file contains a Northern Sami language system, which OpenType features that system activates, or which axes a variable font exposes.

The audience is developers writing font tooling, checkers and web applications, in both the browser and Node, since the library is an ES module that runs in either. The npm package name is lib-font, the description in the package manifest calls it a JS based OpenType font inspector, and the author is Pomax.

Loading a font and asking it what it contains

The load cycle is the familiar one. You construct a Font with a family name, attach handlers, and assign a src, and the parsing happens when the source is set:

js
// Create a font object
const myFont = new Font(`Adobe Source Code Pro`);

// Assign event handling (.addEventListener version supported too, of course)
myFont.onerror = evt => console.error(evt);
myFont.onload = evt => doSomeFontThings(evt);

// Kick off the font load by setting a source file, exactly as you would
// for an <img> or <script> element when building them as nodes in JS.
myFont.src = `./fonts/SourceCodeVariable-Roman.otf`;

The family name is used for stylesheet building, which is the first thing the library does with a font it has loaded: it can generate the @font-face rule for you.

Inside the load handler, the parsed font is available on the event, and the readme is explicit that you should not rely on scoped access to the font variable, because the onload function is not guaranteed to live in the same scope. The font comes back as evt.detail.font.

From there the API is OpenType all the way. The character support check is a method on the font, the tables live under font.opentype.tables, and the GSUB table answers questions about writing scripts, language systems and features:

js
    // We can either rely on scoped access to font, but because the onload function
    // is not guaranteed to live in the same scope, the font is in the event, too.
    const font = evt.detail.font;

    // First, let's test some characters:
    [`a`, `→`, `嬉`].forEach(char => console.log(`Font supports '${char}': ${
        font.supports(char)
    }`));

    // Then, let's check some OpenType things
    const GSUB = font.opentype.tables.GSUB;

The variable font check is the same kind of lookup, through the fvar table, and the readme walks from there to the supported axes.

fromDataBuffer loads a font from bytes, which is the interesting half

The second loading path is the one that makes the library more than a convenience wrapper. A font can be handed over as bytecode rather than fetched from a URL, using the fromDataBuffer function with the buffer and a filename:

js
const myFont = new Font(`Adobe Source Code Pro`);

// Grab file frop drop event or file upload
const file = e.target.files[0];

// Use FileReader to, well, read the file
const reader = new FileReader();
reader.readAsArrayBuffer(file);

reader.onload = function() {
    // Pass the buffer, and the original filename
    myFont.fromDataBuffer(reader.result, file.name);
    myFont.onload = e => {
        // ...
    };
};

The readme frames this around the HTML Drag and Drop API, and the shape of the example makes the intent clear: a user drags a font file onto your page, and your page tells you what is inside it. That is the use case this library exists for, and it is a genuinely useful one for a web-based font inspector, a proofing tool, or a design review workflow where someone drops a candidate typeface in and asks what it actually contains.

Note the ordering detail in the example: fromDataBuffer is called first and the onload handler is attached afterwards, inside the reader's onload. The load is triggered by the buffer call, so the handler has to be in place before the parse finishes, and the nesting reflects that.

The filename argument matters too, since a font file's name can be part of what the library reports back, and the family name passed to the constructor is used for the stylesheet rather than for the file identity.

The constructor options that change what happens on load

The Font constructor takes a family name and an options object, and the options are few but consequential.

fieldname | type | default | description --- | --- | --- | --- skipStyleSheet | boolean | false | Determines whether not to build the `@font-face` stylesheet. styleRules | object | `{}` | A set of key/value pairs representing CSS rules to add to the `@font-face` declaration errorOnStyle | boolean | false | Whether to error out, or merely warn, if the font type cannot be determined from the `src` assignment.

skipStyleSheet is the interesting one for server-side and inspection use, where generating a @font-face rule makes no sense at all, since there is no document to inject it into.

styleRules lets you add extra CSS rules to the generated @font-face declaration, which is how you would set font-display, unicode-range, or any other property the library does not model.

errorOnStyle is a strictness switch. By default, when the font type cannot be determined from the src assignment, the library warns rather than throwing. Set it to true and the failure becomes an error, which matters if your tool is validating a set of files and needs to distinguish a bad font from a font with an unexpected extension.

Error handling itself follows the DOM convention, with f.onerror = evt => ... and an addEventListener('error', ...) form, as the readme shows.

No <font> tag, and no CommonJS or ES5 build

Two absences are deliberate and both are explained.

The first is the element. The library does not offer a <font src="..."> tag, and the readme gives two reasons. Proper custom elements must have a hyphen in their name, and, more importantly, the only DOM related work a <font> tag would be useful for is already handled by <style> for declaring a @font-face and by <link> for importing a @font-face stylesheet. That is a good argument: the element would have added nothing but a naming problem.

The second is the module format. The current library is ES modules only, with no legacy CommonJS version available, and the readme explains the reasoning on both sides. Node LTS 14 and above have native support for ES modules, so there is no need for a CommonJS build, and there are no ES5 browsers in support any more, so there is no need for an ES5 build. If you really need CommonJS, the readme points at Babel's transform-modules-commonjs plugin, and for dead browsers it points at Babel generally.

The older ES5 version of the library, when it was called Font.js, still exists on a v2015 branch of the repository, which is useful if you are maintaining something that predates the current API.

One consequence for build pipelines: the package manifest sets type to module, main and exports both point at ./lib-font.js, and there is no require condition in the export map, so a CommonJS consumer has to go through a transpiler.

Using it in a browser, and the bundle the repository ships

For browser use there are two routes, and the readme spells out the constraints of each.

You can use the pre-built lib-font.browser.js bundle, or you can download the code from the v2.3.2 release, unpack it into a vendor directory and point to the lib-font.js file there. Either way the browser has to be told that this is modern ES module code, and the script tag needs type="module" plus the async attribute:

html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>...</title>
    ...
    <script type="module" src=".../lib-font.js" async></script>
  </head>

  <body>
    ...
  </body>
</html>

The readme also notes the case most people actually want: you will generally want to use the library inside your own script, so your HTML ends up with a script tag pointing at your own module, and that module has an import statement for Font.

The build pipeline that produces the bundle is in the package manifest. The rollup script bundles lib-font.js into lib-font.browser.js with a global name of Font, inlining dynamic imports and marking fs and zlib as external, and terser then minifies the result. The bundle also sets up a global Font object when loaded on its own through its own script tag, which is why the browser usage works without an import.

The repository also contains a fonts directory, an examples directory with a get-font-name script and an introduction script, a testing directory, and a standalone index.html.

MIT licensed, no releases, and an API that is still being written up

The licence is MIT, and the package version in the manifest is 3.0.4. The repository is not archived, and the last push was on 2026-07-26, so the code is still moving, even though the repository has no GitHub releases at all. Version history lives in the package manifest and the changelog rather than in tags.

The documentation gap is the honest caveat, and the readme says so itself. The uplifted library API is still pending. A lot of the functions and properties are pretty easily found if you know your way around an OpenType font already, by looking at the source as well as the tests, but the readme acknowledges that is not ideal, and that API docs will be forthcoming. The API section is expected to keep getting expanded as the API gets consolidated.

That has a practical consequence for anyone evaluating the library. The parts you can rely on from the readme are the constructor, the load cycle, the three options, the error and load events, and the OpenType access pattern. Everything below that, the exact shape of the opentype object, the full list of supported operations on GSUB, the exact behaviour of the stylesheet builder, you have to read from the source and the tests.

The test setup shows how the project is verified, and it is more than unit tests. There is a node test runner over the testing/node and testing/native-node directories, a playwright test over testing/browser/playwright.test.js, a small express server for the browser tests, and a manual test page served with http-server. The package is ESM throughout, and the keywords in the manifest, opentype, font, webfont, parse, inspect and debug, describe the intended use plainly.

Editorial conclusion

lib-font fits a developer building a font picker, a checker, or a web tool that needs to know what a typeface actually contains rather than what its metadata claims, and it does not fit a project that only needs to load a font for rendering, where a plain @font-face rule is enough. Before relying on it, read the source and the tests as the readme itself suggests, since API docs are still pending, and confirm your build target supports ES modules because there is no CommonJS or ES5 build of the current library.

Frequently asked questions

What is lib-font and what does it add to JavaScript?

lib-font adds a new Font() object to the JavaScript toolbox, similar to new Image() for images, so a font can be loaded from a URL or from a byte buffer and then inspected. The package description calls it a JS based OpenType font inspector.

How do I install lib-font and load a font in Node?

Run npm install lib-font and import it with import { Font } from "lib-font". Create a Font with a family name, assign a src to trigger the load, and handle the onload or onerror event.

Can I inspect a font that a user dropped onto my page?

Yes, use the fromDataBuffer function with the buffer and the original filename, which kicks off the font loading from bytecode. The readme shows this with the FileReader API and the HTML Drag and Drop API, with the onload handler attached after the buffer call.

Does lib-font work with CommonJS or old browsers?

There is no legacy CommonJS version of the current library, and Node LTS 14 and above support ES modules natively. There is also no ES5 version, because no ES5 browser is in support any more, and the readme points at Babel for either case.

What can I find out about a font once it is loaded?

You can check character support with font.supports, reach the OpenType tables through font.opentype.tables, query the GSUB table for supported scripts, language systems and features, and check for variable font axes through the fvar table. The full API documentation is still pending according to the readme.

Official sources

  1. Issues
  2. License: MIT
  3. Pomax/lib-font on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pomax-lib-font.svg)](https://hysenlabs.com/projects/pomax-lib-font)

Was this useful?