Generating your own fonts with Fantasicon

Written by Kevin Hougasian

Anyone who’s heard me mention Platform UI knows we make our font icons and bake them right into Platform UI to keep it a one-stop resource. There are some great font packages out there! Do you want to load thousands of icons to get what you’re looking for?

For anyone interested, here is what I found along the way…

The SVGs

I’m not going to go in-depth on generating the SVGs — this is our basic setup:

source default
artboard 4" x 4"
main stroke 24pt
auxiliary stroke 18pt
corner .15"
join round

There are a few tools out there you can evaluate for your workflow. We currently use SVGO but will incorporate outline-stroke in a future build — it remains an evolving process as we learn.

Ok, let’s make some icons

Our first attempt was ok. It generated the font every time but remained a rudimentary approach.

module.exports = {
 inputDir: './src/optimized-icons',
 outputDir: './src/generated',
 fontTypes: ['ttf', 'woff', 'woff2'],
 assetTypes: ['scss'],
 prefix: 'pi',
 name: "platform-icons"
};

Fontasticon has a great Readme and Discord channel. I couldn’t have done this without BOTH of them!

A big issue we faced was adding new icons - we would overwrite previous values making the use of :before and :after impossible. Enter codepoints; But how did they work?

Let’s walk through our current config file .fantasticonrc.js to see how it all comes together. We use Vite to generate Platform UI (with icons) and a stand-alone Platform-icons repo.

module.exports = {
  // We run the main icon directory through SVGO first to 
  // output the inputDir.  
  inputDir: './src/optimized-icons',
  // Where Vite puts things
  outputDir: './public',
  // What font types to generate; If you're solely generating 
  // for the web, you only need woff and woff2
  fontTypes: ['ttf', 'woff', 'woff2'],
  // This is telling Fastasicon what to output:
  // HTML leverages the baked-in handlebars template
  // so does CSS
  // JSON is what you need to stop overwriting your icons!
  assetTypes: ['html', 'json', 'css'],
  // naming convention; user.svg becomes pi-user
  prefix: 'pi',
  // and the tag you're using; <i class="pi-user">
  tag: 'i',
  // the name of the final font files
  name: 'platform-icons',
  fontHeight: 300,
  normalize: true,
    formatOptions: {
    json: {
      indent: 2
    }
  },
  // Handlebars templates for your assetType output
  templates: {
    html: './src/templates/html.hbs',
    css: './src/templates/css.hbs'
  },
  // And where you're outputting these files
  pathOptions: {
    json: './src/platform-icons.json',
    html: './index.html'
  }
};

Ok, that’s what you need to generate your first font file. Your second font file needs more.

Now that you’ve generated ./src/platform-icons.json, which you specified in assetTypes and pathOptions, you need to require the codepoints path and use it in your config file.

// Before module.exports = {...}
const codepoints = require('./src/platform-icons.json');
// And `codepoints` somewhere in the export

Your final config file should look like this:

const codepoints = require('./src/platform-icons.json');
module.exports = {
  inputDir: './src/optimized-icons',
  outputDir: './public',
  fontTypes: ['ttf', 'woff', 'woff2'],
  assetTypes: ['html', 'json', 'css'],
  prefix: 'pi',
  tag: 'i',
  name: 'platform-icons',
  fontHeight: 300,
  normalize: true,
  formatOptions: {
    json: {
      indent: 2
    }
  },
  codepoints,
  templates: {
    html: './src/templates/html.hbs',
    css: './src/templates/css.hbs'
  },
  pathOptions: {
    json: './src/platform-icons.json',
    html: './index.html'
  }
};

That’s it.

You now have a font that won’t overwrite codepoint values. When you add a new SVG, it will append to the bottom of the list.

I hope this helps someone! It was a journey for me.

Happy fonting!

Published February 27, 2023 by

undefined avatar
Kevin Hougasian Lead Frontend Developer

Suggested Reading