How to Add Custom Fonts in Next.js and Tailwind CSS Templates
Tags: nextjs, tailwindcss, tutorial, webdev
Published: 2023-07-25 08:47:09

Since the launch of Cruip, thousands of developers have purchased our templates, and many of them have asked us for assistance to personalize them according to their needs.

We love helping our customers achieve the best possible outcome with our products, but since we are a small team of two and our customer base continues to grow (thankfully), we decided to start a series of articles/guides based on your most common customization questions. This way, we hope to optimize some of our time (that we can invest in creating more products) and offer an even better service to you!

Let’s start with a guide on **how to customise the fonts of Tailwind CSS templates built with Next.js**. Step by step, we’ll walk you through font management and show you how to create custom versions of the templates that will make them truly one-of-a-kind.

As you may know, the React versions of Cruip templates are built with **Tailwind CSS** and use **Next.js 13’s new app directory** (App Router). Additionally, at the time of writing, all templates use Google Fonts and, in some cases, local fonts. Therefore, we’ll illustrate [how to add a new Google font](#adding-a-new-google-font-to-a-template), [replace the current one](#replacing-one-google-font-with-another), [use local fonts](@using-a-local-font), and even [utilize system fonts](#using-a-system-font) to optimize your website’s performance.

How we use fonts in Cruip templates
-----------------------------------

Before diving into practical examples, let’s first take a brief overview of how we use fonts in Cruip templates. In general, we define the **main font-family on the body tag**. In cases where we also use a secondary font, we directly define it on each element using Tailwind CSS classes.

Take our [Tidy template](https://cruip.com/tidy/), for example. The base font is [Inter](https://fonts.google.com/specimen/Inter), defined on the body tag with the `font-inter` class. For headings, however, we use the serif font [Playfair Display](https://fonts.google.com/specimen/Playfair+Display), which is defined on each element (`h1`, `h2`, and `h3`) using the `font-playfair-display` class.

Now, someone might object and ask why we didn’t define the font for headings directly in CSS to avoid repeating it for each element. It would have been a sensible choice, indeed, but we preferred to embrace the philosophy of Tailwind CSS, which encourages the use of classes to define element styles. Moreover, this way, it’s easy to switch to a different font for headings by simply modifying the class.

Adding a new Google Font to a template
--------------------------------------

Let’s say we want to add a third font for specific parts of the template, and that font is [Nothing You Could Do](https://fonts.google.com/specimen/Nothing+You+Could+Do). First, we need to load the font using `next/font`. Normally, we use the main `layout.tsx` file for this. However, if we know that we’ll only need this font in a specific component, it’s good practice to load it directly in that component. This way, we avoid loading unnecessary fonts throughout the entire website.

To use the font across all pages, let’s add the following code to the `layout.tsx` file:

```tsx
  import { Nothing_You_Could_Do } from 'next/font/google'
```

With the code above, we imported the font **Nothing You Could Do**. Keep in mind that for Google Fonts with multiple words in their names, it’s necessary to replace spaces with underscores, and each word should start with a capital letter. In this case, the font is called “Nothing You Could Do”, so we need to use `Nothing_You_Could_Do` to import it. If you’re unsure about the font name, you can always check the exports in `next/font/google` within the `node_modules` folder.

Now let’s define a variable for the font:

```tsx
  const nycd = Nothing_You_Could_Do({
    subsets: ['latin'],
    variable: '--font-nycd',
    weight: '400',
    display: 'swap'
  })
```

The variable name is arbitrary but should be consistent with what we’ll define in the Tailwind CSS configuration file.

Next, let’s add the variable to the container element where we want to use the font, which in this case is the `body` element:

```tsx
  <body className={`${inter.variable} ${playfair.variable} ${nycd.variable} font-inter antialiased bg-white text-slate-800 tracking-tight`}>
```

Finally, we need to add the font to the Tailwind CSS configuration file. To do this, open the `tailwind.config.js` file and add the `font-nycd` variable to our theme:

```tsx
  fontFamily: {
    inter: ['var(--font-inter)', 'sans-serif'],
    'playfair-display': ['var(--font-playfair-display)', 'serif'],
    'nycd': ['var(--font-nycd)', 'cursive'],
  }
```

Great! Now we can use the font on any HTML element by simply adding the `font-nycd` class, for example:

```tsx
  <p className="font-nycd">Hello world!</h1>
```

Replacing one Google Font with another
--------------------------------------

Let’s stick with the **Tidy** template and suppose we want to replace the **Playfair Display** font used for headings with the font [Poppins](https://fonts.google.com/specimen/Poppins).

First, in the `layout.tsx` file, we’ll modify the font import. So this line:

```tsx
  import { Inter, Playfair_Display } from 'next/font/google'
```

becomes this:

```tsx
  import { Inter, Poppins } from 'next/font/google'
```

Next, we’ll remove this code block:

```tsx
  const playfair = Playfair_Display({
    subsets: ['latin'],
    variable: '--font-playfair-display',
    display: 'swap'
  })
```

and replace it with this:

```tsx
  const poppins = Poppins({
    subsets: ['latin'],
    variable: '--font-poppins',
    display: 'swap'
  })
```

Finally, in the `layout.tsx` file, we’ll replace the `playfair` variable with `poppins`. So this line:

```tsx
  <body className={`${inter.variable} ${playfair.variable} font-inter antialiased bg-white text-slate-800 tracking-tight`}>
```

becomes this:

```tsx
  <body className={`${inter.variable} ${poppins.variable} font-inter antialiased bg-white text-slate-800 tracking-tight`}>
```

Now, let’s edit the `tailwind.config.js` file and replace the fonts there as well. So this code block:

```tsx
  fontFamily: {
    inter: ['var(--font-inter)', 'sans-serif'],
    'playfair-display': ['var(--font-playfair-display)', 'serif'],
  },
```

changes to this:

```tsx
  fontFamily: {
    inter: ['var(--font-inter)', 'sans-serif'],
    poppins: ['var(--font-poppins)', 'sans-serif'],
  },
```

The final step is to use the right class for the Poppins font on each heading tag. To do this quickly and accurately, we can do a global search for the string “font-playfair-display” and use the “Replace all” function to replace it with “font-poppins”. This way, we’ll replace all instances of `font-playfair-display` with `font-poppins`. Usually, all editors (we use VS Code) have a feature to search for a string in specific files. Since we want to make the replacement only in .tsx files, we can specify `*.tsx` in the “files to include” field.

Using a local font
------------------

To add a touch of uniqueness to our template design, we’ve used some fonts that are not available in the Google Fonts library, such as [Aspekta](https://github.com/ivodolenc/aspekta), or [Cabinet Grotesk](https://www.fontshare.com/fonts/cabinet-grotesk).

These fonts are available in **.woff2** format and can be easily included in any other Next.js template. Let’s jump into a practical example right away.

Suppose we want to use the bold version of the Aspekta font for the headings in the Tidy template. We’ll download the font from the [Github repository](https://github.com/ivodolenc/aspekta) and include the file **Aspekta-700.woff2** in the `public/fonts` folder of our project.

Next, we import the font into the `layout.tsx` file like this:

```tsx
  import localFont from 'next/font/local'
  const aspekta = localFont({
    src: [
      {
        path: '../public/fonts/Aspekta-700.woff2',
        weight: '700',
      },       
    ],
    variable: '--font-aspekta',
    display: 'swap',  
  })
```

Let’s add the variable `aspekta` to the classes of the `body` element:

```tsx
  <body className={`${inter.variable} ${aspekta.variable} ${nycd.variable} font-inter antialiased bg-white text-slate-800 tracking-tight`}>
```

At this point, let’s modify the `tailwind.config.js` file like this:

```tsx
  fontFamily: {
    inter: ['var(--font-inter)', 'sans-serif'],
    'aspekta': ['var(--font-aspekta)', 'sans-serif'],
  }
```

Finally, to use the new font for the headings, we need to replace the class `font-playfair-display` with `font-aspekta` on each heading tag. Once again, we’ll do a global search for the string “font-playfair-display” and use the “Replace all” function to replace it with “font-aspekta”.

Using a system font
-------------------

In this last step of the guide, we’ll explain how and when to use a system font for your Next.js website.

Although Next.js 13 ensures optimal font loading management, avoiding [Cumulative Layout Shift (CLS) issues](https://web.dev/cls/), using system fonts offers additional **advantages in terms of performance and site loading speed**. Since these fonts are already installed in the operating system or device, they don’t require any additional downloads like Google Fonts or local fonts.

Furthermore, using a system font ensures that **the text appearance is consistent with the rest of the operating system or device**. This is certainly an advantage, but it can also be a limitation since the system font may not align with your website’s design. In other words, you may not have full control over the typography design of your site.

Another factor to consider is that **system fonts may not support specific special characters or symbols** you may want to use. In such cases, you may need to resort to external or local fonts.

Ultimately, if custom text design is not a priority and the main goal is to ensure good readability and consistent presentation, using a system font can be a practical choice. There are many popular websites using system fonts, from GitHub to Booking, from Wikipedia to Medium, so you’ll be in good company!

For further insights, we recommend reading this [excellent article](https://css-tricks.com/snippets/css/system-font-stack/).

Using system fonts is extremely simple: **no font import is necessary**! So, let’s assume we want to use only system fonts in Tidy. To do this, we’ll remove the following code blocks from the `layout.tsx` file:

```tsx
  import { Inter, Playfair_Display } from 'next/font/google'
  const inter = Inter({
    subsets: ['latin'],
    variable: '--font-inter',
    display: 'swap'
  })
  const playfair = Playfair_Display({
    subsets: ['latin'],
    variable: '--font-playfair-display',
    display: 'swap'
  })
```

Let’s also remove the `inter` and `playfair` variables from the classes of the `body` element, as well as the `font-inter` class:

```tsx
  <body className={`antialiased bg-white text-slate-800 tracking-tight`}>
```

Next, in the `tailwind.config.js` file, we can safely remove the entire object that defines the font families in use:

```tsx
  fontFamily: {
    inter: ['var(--font-inter)', 'sans-serif'],
    'playfair-display': ['var(--font-playfair-display)', 'serif'],
  },
```

Finally, using a global search, we’ll remove all the now unnecessary classes defined as “font-playfair-display”.

After completing these steps, we suggest testing the typography of your website on different devices and operating systems to ensure that the text design meets your expectations.

Conclusions
-----------

Choosing the right font can significantly impact the overall user experience and convey the intended message effectively. Whether you opt for Google Fonts, local fonts, or system fonts, each option has its own advantages and considerations.

We hope that this guide has been helpful in showing you how to customize our [Tailwind CSS templates](https://cruip.com). Happy coding!