DEV Community

Thomas Ledoux
Thomas Ledoux

Posted on

The best way to load and use Google Fonts in Next.js + Tailwind

I was setting up a new project today with Next.js and tailwindcss, and I had to use Roboto as a font.

Since it's a Google Font, I was looking into the best way to load a font from an external URL (since the fonts are available through a CDN, I don't bother hosting them myself).

The following article explains this very thoroughly: https://csswizardry.com/2020/05/the-fastest-google-fonts.

From this article you can derive the following snippet:

<link rel="preconnect"
      href="https://fonts.gstatic.com"
      crossorigin />

<!-- [2] -->
<link rel="preload"
      as="style"
      href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" />

<!-- [3] -->
<link rel="stylesheet"
      href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
      media="print" onload="this.media='all'" />

<!-- [4] -->
<noscript>
  <link rel="stylesheet"
        href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" />
</noscript>
Enter fullscreen mode Exit fullscreen mode

Also note how I only include the weights I'm going to be using (400 & 700) to reduce the size of the font we're loading.

So, how do we implement the above snippet into our Next.js application?
That's quite simple!
In your /pages folder, you should have a _document.js/.tsx file.
In this file, we can easily adapt the <head> section using the next/head module. This will be applied on every page by Next.js.

import Document, {
  DocumentContext,
  Html,
  Head,
  Main,
  NextScript,
} from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const initialProps = await Document.getInitialProps(ctx)

    return initialProps
  }

  render() {
    return (
      <Html>
        <Head>
          <link
            rel="preconnect"
            href="https://fonts.gstatic.com"
            crossOrigin="true"
          />
          <link
            rel="preload"
            as="style"
            href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
          />
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
            media="print"
            onLoad="this.media='all'"
          />
          <noscript>
            <link
              rel="stylesheet"
              href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
            />
          </noscript>
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument
Enter fullscreen mode Exit fullscreen mode

Now the Next.js part is done. The font is being loaded, yay!
The next and final part is actually using the font in Tailwind, and applying it to all our sans-serif text (since Roboto is a sans-serif font).

This is super easy in Tailwind, this just requires an extension of the default theme:

const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Roboto', ...defaultTheme.fontFamily.sans],
      },
    },
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

I only needed to add the sans property of the fontFamily object to include the Roboto font, and add the other sans-serif fonts from the default theme as fallbacks.

There you have it! Optimized font loading in your Next.js application with Tailwind :-)
Enjoy.

Discussion (13)

Collapse
andrej_gajdos profile image
Andrej Gajdos

I am getting Lighthouse warning message:

Warnings: A <link rel=preconnect> was found for "fonts.gstatic.com" but was not used by the browser. Only use preconnect for important origins that the page will certainly request.

Collapse
thomasledoux1 profile image
Thomas Ledoux Author

Can you see any requests going to fonts.gstatic.com in your network tab?
Maybe Google changes the CDN for their fonts...

Collapse
andrej_gajdos profile image
Andrej Gajdos • Edited on

Yes, I see imgur.com/a/zAnDtoE

Thread Thread
thomasledoux1 profile image
Thomas Ledoux Author

That’s strange… not sure why it’s giving that warning then

Thread Thread
andrej_gajdos profile image
Andrej Gajdos

I guess Lighthouse changed something, but thanks for the blog post anyway.

Collapse
marcvangend profile image
Marc

Thanks for sharing. AFAIK, these is no pages/_document file by default, you have to create it yourself to override the default behavior.
But I'm wondering: is it really necessary here to start using a customized _document? You could also use next/head in pages/_app to add the code snippet to the head.

Collapse
pabloverduzco profile image
Pablo Verduzco

I think it is totally allowed.

Check this out: npmjs.com/package/next-google-font...

Collapse
thomasledoux1 profile image
Thomas Ledoux Author

Hey Marc,

I haven't tested this with pages/_app yet, but I assume it would work too since you would inject the code into the

section with next/head on every page.
Collapse
gabrielmlinassi profile image
Gabriel Linassi

There's an eslint rule that recommends to add it to the _document file. See nextjs.org/docs/messages/no-page-c...

Collapse
stevereid profile image
Steve Reid

Typescript doesn't like the onLoad="this.media='all'"
I get:
Type 'string' is not assignable to type 'ReactEventHandler'.
Any ideas?

Collapse
thomasledoux1 profile image
Thomas Ledoux Author

I noticed this too, but chose to ignore it:

<link
  rel="stylesheet"
href="https://fonts.googleapis.com/css2family=Podkova:wght@400;500;700&Roboto:wght@400;500;700&display=swap"
 media="print"
 // @ts-ignore
 onLoad="this.media='all'"
/>

Enter fullscreen mode Exit fullscreen mode
Collapse
ninest profile image
ninest

Thanks for the write up! Is it faster if I download the fonts and reference them locally rather than importing from fonts.google.com?

Collapse
thomasledoux1 profile image
Thomas Ledoux Author

My pleasure!
I'm guessing this would be faster, as you don't have to connect to an external source to fetch the fonts.
But the CDN of Google is very fast, so I'm not sure if the difference will be noticeable.
If you want to host your fonts locally, have a look at this site: google-webfonts-helper.herokuapp.c...