Adding custom fonts in Tailwind

Cover Image for Adding custom fonts in Tailwind

A good font can say it all. This is especially the case when designing applications!

TailwindCSS enables us to configure styles and apply them using modular, dynamically-determined utility classes. This balances the convenience of inline styling with the sustainability of managed CSS. Fonts are a great way to dip our toes into the sorcery at work here.

In this tutorial, we will:

  1. Begin by choosing an import method
  2. Configure our custom font at app level
  3. Apply the Tailwind class in our markup

Important imports: Hosted or self-hosted?

But first, a decision. There are two ways to incorporate a custom font: linking to an externally hosted web font resource or adding a self-hosted local copy of the font. Our choice determines what we need to do for setup.

Linking to a hosted web font

Web font providers like Google Fonts manage all of the dirty work of making fonts standardized and available. They also give you control over the exact font(s) you would like to use. However, you will need to make external requests to access them.

Most times, you should import these custom fonts using a <link> tag in the <head> of our site. This will cause JavaScript to parse data related to the font immediately, before loading any page contents.

In the instance of Google Fonts, this might look like adding the following metadata:

<head>
...
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">
</head>

On the flip side, you should avoid @import rules when you can. The font will load only after fetching the resource, which can cause inconsistent rendering, such as a flash of unstyled text to users. Web font providers often expose platform-specific versions for fonts, too, so an unreliable load can lead to broken fonts on different browsers if your build squashes your inline @import instances.

Self-hosting a local file

Alternatively, you can import a font using an .otf, .ttf, or other file placed in the public directory. By doing this, we no longer need to make a request to load our fonts, which cuts out a dependency.

While this makes the font immediately available, it also adds weight to our application. Additionally, self-hosted font files are not standardized. On top of format differents, some may contain the entire set of styles when you only need to use one, while other fonts may have each style broken up into its own file. In this case, managing the necessary imports can become unruly. As noted, web font providers abstract away this messiness.

After giving the file a home in public, turn to your global Tailwind CSS file, e.g., index.css. We will use the @font-face decorator to bring in the custom font using a local path. In the example below, we are bringing in the "light" style of the font Roboto.

// Within index.css...
@tailwind base;
@tailwind components;
@tailwind utilities;

@font-face {
  font-family: "Roboto";
  src: url("../public/fonts/Roboto-light.ttf");
}

Configuration

Next, we will extend the font as a utility class to use in the application. In other words, this is where we determine the name of the class, and then tell Tailwind to make a connection to our font. This step is the same regardless of how you imported the font.

In tailwind.config.js, within module.exports.theme.extend, add an object called fontFamily.

  • For the key, put the intended name of the utility class as a string. For instance, setting sans as the key creates the class font-sans.
  • For the value, create an array with at least two string values as you normally would in CSS. The first will name the custom font, while the second will determine a fallback font (usually, a default system font) for the browser to use in case the font does not load. You can include multiple fallbacks here if you prefer.
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        'sans': ['Roboto', 'sans-serif'] 
      },
    },
  },
  ...
}

Naming conventions

You may notice that we used the name sans for our utility class. Why didn't we use roboto instead?

It's all about future-proofing! By using Tailwind, we can dramatically consolidate the styles we use on our site. This means that we only need to update the configuration of font-sans to change the font used across everywhere we use the utility class. It makes sense then that we would like to name the class descriptively so it can adapt to change. Here, our class will be used for anywhere we want to use a sans-serif font.

Use the utility class

At this point, only implementation remains. Tailwind generates a utility class that we can immediately use.

<p className="font-sans">
  Well-Preserved, 30,000-Year-Old Baby Woolly Mammoth Emerges From Yukon Permafrost
</p>

And voila! The text will render with our custom font.

Wrapping up

Tailwind, like other utility-first styling frameworks, centralizes your styling. For some developers, this introduces a set of constraints that make it easier to create a uniform design in their applications. Custom fonts demonstrate just one way we can leverage Tailwind's flexibility, as we can begin to think of the ways we may apply similar patterns to spacing, sizing, and color.

Check out this additional reading: