DEV Community

Cover image for Self-hosted fonts with Next.js and Material UI
Elisabeth Leonhardt
Elisabeth Leonhardt

Posted on

Self-hosted fonts with Next.js and Material UI

A few days back, I needed to import some .woff2 files into my Next.js project and pass them to Material UI. It took me a while to figure out how to do it, so here is a quick step-by-step tutorial for everyone who needs it and my forgetful future self.

1. Get a fresh next.js project up and running

You know the drill: Run npx create-next-app fonts, cd into the new directory and run npm run dev to see the Next.js starter in your browser window on localhost:3000.

2. Install Material UI

Once you have your project open, install Material UI with npm install @mui/material @emotion/react @emotion/styled (see the installation docs for any questions you might have regarding the installation or if some time has passed since this tutorial was published).

3. Locate your font-files

Find the public folder inside the root of your project directory. You can put your fonts directly inside this folder, although I recommend creating a subfolder called fonts, especially if your project has the potential to grow a bit.

I put my fonts inside a fonts directory inside the public directory

I took a snapshot of my folder structure here: For now, my fonts have their folder and everything else is just dumped inside the public folder since I don't have many static files for now.

4. Use your font inside CSS

Now you have to give your CSS access to your font, which you do by using the font-face rule. This is an instruction for your CSS to get the font from where you point it to, similar to the src attribute of an img tag.

The source can be inside the project or you can instruct the code to download the source from a CDN, Google Fonts being one of the more popular ones. (If you actually wanted to do that, here are the instructions).

The font-face rule should be put inside a global CSS file: I put mine into the global.css Next.js had already created for me: you can find it inside styles > global.css

@font-face {
  font-family: GothamMedium;
  src: url("/fonts/GothamRnd-Medium.woff2");
  format: ("woff2");
  font-display: swap;
Enter fullscreen mode Exit fullscreen mode

You declare the name you will use for your font, in my case GothamMedium, the source URL, and the format. Be aware that the source URL is the relative path inside the public folder, so you shouldn't specify public/ or something like that in the source and then be confused like me because the code didn't find the font.

The font-display: swap instruction is there to improve the performance of the page. It will tell the browser to render text right away with a system font and later repaint the content as soon as the custom font is loaded.

If you did everything right, you already should be able to use your font! Render hello world in a paragraph tag to see your loaded font in action:

Hello world displayed with the self-hosted font

5. Use your font inside MUI

As the last step, go inside the _app.js file and declare a theme and a ThemeProvider. Let's first declare an empty theme and look at the difference between the font used by the paragraph tag vs. the font used by the Typography component.

import "../styles/globals.css";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import { Typography } from "@mui/material";

export let theme = createTheme({});

function MyApp({ Component }) {
  return (
        <ThemeProvider theme={theme}>
            <Typography>Hello world from typography component</Typography>
            <p>Hello world from paragraph tag</p>
            <Component {...pageProps} />

export default MyApp;
Enter fullscreen mode Exit fullscreen mode

MUI is not using the font yet

So the font is already working, but Material UI has to pick it up yet. This can be done by simply declaring the font inside Material UI's theme object. Just use the same name for the font you used earlier in the CSS:

export let theme = createTheme({
  typography: {
    fontFamily: "GothamMedium, sans-serif",
Enter fullscreen mode Exit fullscreen mode

Taking a look at the browser, we can now see that Material UI is already using the loaded font because both Hello worlds (is that the Hello world plural?) look the same.

MUI is using the imported font

That's it! I hope it helped and saved you some time. Have a great week!

Discussion (1)

twrigh404g profile image

Is there a way to import custom font-faces/typography?