# svgtofont and the case for shipping icons as a font file

> svgtofont reads a directory of SVG icons and compiles them into TTF, EOT, WOFF, WOFF2 and SVG font files, with a CLI, a programmatic API and a CSS generator. It fits teams that need one request instead of twenty icon files, and it carries the usual icon font costs, including colour icons that need special handling.

**jaywcjlove/svgtofont** — Read a set of SVG icons and ouput a TTF/EOT/WOFF/WOFF2/SVG font.

- Repository: https://github.com/jaywcjlove/svgtofont
- Website: https://jaywcjlove.github.io/svgtofont
- Stars: 728 · Forks: 103
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/jaywcjlove-svgtofont

## A font file instead of a folder of SVG requests

svgtofont reads a set of SVG icons and outputs a TTF, EOT, WOFF, WOFF2 or SVG font, as the package description says. The homepage is a documentation site, and the project is written in TypeScript.

The problem it solves is the one every icon set eventually hits. You have forty icons as individual SVG files, and every page that shows a toolbar loads them. The browser requests each one, the markup repeats a path or a use reference, and the icons cannot inherit colour from the text because they are images rather than text.

A font solves both problems at once. The icons become glyphs, so they are requested as a single font file, and because they are text they take the current colour and the current font size without any of that being configured per icon. The cost is that each icon now needs a character assigned to it, and that mapping has to be documented so that a developer can write `icon-settings` and get the right glyph.

That mapping is the part a tool like this exists to handle, because getting it wrong produces a page full of blank boxes or a font where every icon renders as the wrong symbol. svgtofont writes the font, and it generates the CSS with the class names, the character codes and the content declarations, so the mapping is produced by the same run that produced the font.

The package manifest describes itself as converting SVG to TTF, EOT, WOFF, WOFF2 and SVG format fonts, and the keyword list covers the whole chain: `svg2ttf`, `ttf2eot`, `ttf2woff`, `ttf2woff2`, `ttf2svg`, plus `webfont`, `iconfont` and `font-face`.

## The CLI takes a source directory and a font name

The package ships a binary named `svgtofont`, pointing at `lib/cli.js`, and the manifest contains a working example of the invocation:

```bash
node lib/cli.js --sources ./examples/example/svg --output ./dist --fontName uiw-font
```

Three flags, and they are the whole interface worth knowing. `--sources` points at the directory of SVG files, `--output` at where the generated files go, and `--fontName` sets the name of the resulting font, which becomes the font family name in the CSS and the name you use in your `font-family` declaration.

The same invocation is available as a package script, so you can run it without remembering the flags:

```bash
npm run example:cli
```

and the underlying script is `node lib/cli.js --sources ./examples/example/svg --output ./dist --fontName uiw-font`.

There are other example scripts in the manifest for the other entry points. `npm run example` runs the main example, `npm run example:simple` runs a simpler variant, and `npm run example:templates` runs the templates example. The `pretest` script runs all three before the test suite, which is a useful hint about how the project validates itself: the examples are the test fixtures.

The library entry point is separate from the CLI. The main entry is `./lib/index.js` with types at `./lib/index.d.ts`, and there is a second export path `./lib/utils` with its own type declarations, so utility helpers can be imported without pulling the main module. The package is ESM, the `type` field is `module`, and the engines field requires Node 18.0.0 or newer.

## Configuration lives in the package.json under an svgtofont key

There is an unusual and rather pleasant detail in the manifest: the tool has its own configuration block inside package.json, under a top level `svgtofont` key.

The shipped default is minimal:

```json
  "svgtofont": {
    "css": {
      "fontSize": false
    }
  }
```

That `fontSize` setting under `css` controls whether the generated CSS carries a font size for the icon classes, and it is off by default. The reasoning is straightforward once you see it: an icon font class that sets a font size will override the size of the surrounding text, so a toolbar of icons at a fixed size stops resizing with the text around it. Leaving it off lets the icons inherit whatever size the surrounding markup sets.

The choice to put the configuration in package.json rather than in a separate file is worth noting on its own. The tool is meant to live in the build of the project that uses the icons, and package.json is already the file that describes that project's build. A separate config file would be one more file to keep in step, and one more thing to merge when the icon set changes.

The manifest also shows the shape of the output. The `files` array ships only `lib` and `src`, and the `keywords` array lists the formats the tool emits, including `base64` and `css`, which is the other half of the story: the tool does not only produce font binaries, it produces the stylesheet that maps class names to glyphs.

## The examples show the cases the format cannot handle well

The repository has five example directories, and the names describe the problems the tool has to solve rather than the features it offers.

There is `examples/example/`, the main one, which the package scripts point at. There is `examples/templates/`, run by the `example:templates` script. And then there are two directories with hashes in their names, `examples/example#211/` and `examples/example#233/`, which are issue numbers, and `examples/multicolor/`.

Those hashed directories are the interesting ones. A directory named after a GitHub issue is a regression case, a set of inputs that once broke the tool. Two of them existing means the tool has broken on real input at least twice, and each fix added a directory so the case stays covered. That is a more honest signal about the reliability of SVG to font conversion than a feature list.

The `multicolor` directory is the other one. Fonts are single colour by construction, a glyph is a shape filled with the text colour, and a multi colour icon is not expressible in a normal font file. The existence of a dedicated example means the tool has some answer to that, and the answer will be a compromise of some kind, whether that is layering several font files, using a colour table, or falling back to a different output format for those glyphs. A project that ships a `multicolor` example is at least being straight about the problem rather than pretending it does not exist.

The practical advice follows from this. If your icon set is monochrome, this tool is straightforward. If it has coloured icons, look at the `multicolor` example before committing, because that is where the format and the tool are both working against the grain.

## Where inline SVG beats a font

There is a real question of whether you need a font at all, and for a small icon set the answer is often no.

Inline SVG, where the SVG markup sits in the document, gives you one file fewer, no extra request, and no character mapping to document. The colour comes from `currentColor` just as it does with a font, so the main styling argument for fonts does not apply. Modern browsers handle SVG in markup well.

What the font approach still wins on is the number of requests and the styling surface. With a font, the browser fetches one file for the whole set. With inline SVG, the markup grows with every icon and the document itself gets larger, and if the same icon appears ten times on a page, that markup appears ten times unless the icon is a symbol in a sprite. That is a real difference on a dense toolbar or a data table, and it is the difference that makes the font approach worth it at forty icons and not worth it at five.

There is also a correctness argument. Icons that carry meaning, a delete icon or a warning triangle, are often better as text with a screen reader label than as a glyph whose accessible name has to be added separately. A font does not solve that, and a tool that generates a CSS class per icon does not make it worse either, but it is worth remembering that a font is a presentation choice and not an accessibility one.

The other limitation to consider is the character mapping. Every icon occupies a character code in the font, and if a designer later adds an icon in the middle of the set rather than at the end, every code after it can shift, which breaks any saved user preference or shared URL that referenced a code. A stable mapping means appending only, or a build step that writes the mapping to a versioned file the rest of the project reads. The tool generates the CSS for you, so this is handled as long as the generated CSS is the single source of truth.

## Against a maintained icon package, the difference is who owns the set

The alternative is to use an existing icon font package from a design system, or to ship a hand written SVG component library. The difference in approach is ownership.

An existing icon package gives you a curated set with consistent geometry, weights and naming, a maintained CSS, and documentation for every icon. You do not run a build step, and you do not own the mapping. The cost is that you accept the design decisions of the package, you cannot adjust an icon that does not match your product, and you take a dependency on someone else's release cadence.

A hand written SVG component library, where each icon is a component that takes a size and a colour prop, gives you the most control and no font at all, but every developer has to import the right component, and you have built the component layer yourself.

svgtofont sits between those. It assumes you have decided on your own icon set, which is exactly the situation after a design system has produced its assets as SVG files and someone has to turn them into something the web can consume. It is the build step for your own assets rather than a substitute for them.

The tooling around it is conventional and modern, which matters for a build dependency. TypeScript sources compiled with `tsbb`, tests with `tsbb test` and `tsbb test --coverage`, type checking with `tsc --noEmit`, a `watch` script for development, and Renovate for dependency updates, with a `renovate.json` at the root. The MIT licence and the Node 18 engine requirement mean it drops into most modern build setups without argument.

So the decision is simple. If you want someone else's icons, use their package. If you have your own icons and want them in one file, this is the tool. If you have six icons, you do not need either.

## Conclusion

svgtofont fits a team that has accumulated a set of SVG icons and needs them delivered to the browser as one font file, with the CSS and the character mapping generated for you rather than maintained by hand. It is the wrong choice if you have a handful of icons, because inline SVG is simpler, and it is the wrong choice if your icons are multi colour, since the `multicolor` example in the repository exists to work around a limitation of the font format itself. Before adopting, verify two things: that the icon set you have is consistently sized and structured, since the tool maps glyphs to characters and expects a regular input, and that the `multicolor` example covers your case if you have coloured icons. The code is MIT licensed, the current release is v6.5.3 from 2026-06-30, and the last push was on the same day.

## FAQ

### What does svgtofont do?

It reads a set of SVG icons and outputs a TTF, EOT, WOFF, WOFF2 or SVG font, and generates the CSS that maps class names to the glyph characters. The package description is "Converts SVG to TTF/EOT/WOFF/WOFF2/SVG format fonts."

### How do I run svgtofont from the command line?

The binary is `svgtofont`. The example invocation is `node lib/cli.js --sources ./examples/example/svg --output ./dist --fontName uiw-font`, and the package ships it as the `example:cli` script, so `npm run example:cli` does the same thing.

### How is svgtofont configured?

Configuration lives in the package.json under a top level `svgtofont` key. The shipped default sets `css.fontSize` to false, which means the generated CSS does not set a font size on the icon classes so the icons inherit the surrounding text size.

### Can svgtofont handle multi colour icons?

The repository includes an `examples/multicolor/` directory, and a font file is single colour by construction, so multi colour output is a special case rather than the default path. There is also `examples/example#211/` and `examples/example#233/`, which are named after issue numbers and hold input cases that once broke the tool.

### What are the system requirements for svgtofont?

The package is written in TypeScript, is an ESM module, and its engines field requires Node 18.0.0 or newer. It ships both a library entry point at the package root and a secondary `./lib/utils` export path, and the published files are `lib` and `src`.

## Sources

- [jaywcjlove/svgtofont on GitHub](https://github.com/jaywcjlove/svgtofont)
- [License: MIT](https://github.com/jaywcjlove/svgtofont/blob/master/LICENSE)
- [Project website](https://jaywcjlove.github.io/svgtofont)
- [README](https://github.com/jaywcjlove/svgtofont/blob/master/README.md)
- [Releases](https://github.com/jaywcjlove/svgtofont/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jaywcjlove-svgtofont
