Next.js Discord

Discord Forum

Is there no way to use local fonts if you have a custom _document?

Answered
Great black wasp posted this in #help-forum
Open in Discord
Great black waspOP
Using tailwind and page router.
Answered by English Lop
Good bump 😄

First fix fonts.ts import paths:
{
    path: '../public/fonts/gilroy/gilroy-bold.woff2',
    weight: '600', // font-semibold
    style: 'normal',
  },
  {
    path: '../public/fonts/gilroy/gilroy-bolditalic.woff2',
    weight: '600', // font-semibold
    ...


Then to registry css variable name, must use class in parent component, there 2 ways:

First way:

Define class in _document.tsx (fonts css will not be imported, just variables):
import {gilroy} from '@styles/fonts'
<Html lang='en-US' className={gilroy.variable}>
...


If using in _document.tsx _app.tsx should import all fonts css:
import '@styles/fonts'
import '../styles/globals.css'
...


Second way:

In _app.tsx wrap layout in tag (then not need import in _document.tsx), for example:
import {gilroy} from '@styles/fonts'
import '../styles/globals.css'
...
  return <div className={gilroy.className}>{getLayout(<Component {...pageProps} />)}</div>
View full answer

13 Replies

Great black waspOP
So far no luck. I got it so the fonts show up now in the resources tab while inspecting the page, but they're still not loading. My most recent attempt was this:

import { dempsey } from '@styles/fonts/fonts'
 {getLayout(
        <Component
          {...pageProps}
          className={`${dempsey.variable} font-dempsey`}
          style={{ ...pageProps, '-font-sans': dempsey.style.fontFamily }}
        />,
      )}


Which obfuscates the font name and places it in /next/static/chunks
Great black waspOP
.
Bump
English Lop
Good bump 😄

First fix fonts.ts import paths:
{
    path: '../public/fonts/gilroy/gilroy-bold.woff2',
    weight: '600', // font-semibold
    style: 'normal',
  },
  {
    path: '../public/fonts/gilroy/gilroy-bolditalic.woff2',
    weight: '600', // font-semibold
    ...


Then to registry css variable name, must use class in parent component, there 2 ways:

First way:

Define class in _document.tsx (fonts css will not be imported, just variables):
import {gilroy} from '@styles/fonts'
<Html lang='en-US' className={gilroy.variable}>
...


If using in _document.tsx _app.tsx should import all fonts css:
import '@styles/fonts'
import '../styles/globals.css'
...


Second way:

In _app.tsx wrap layout in tag (then not need import in _document.tsx), for example:
import {gilroy} from '@styles/fonts'
import '../styles/globals.css'
...
  return <div className={gilroy.className}>{getLayout(<Component {...pageProps} />)}</div>
Answer
Great black waspOP
@English Lop That worked!!! Thank you so much. It's been literal days of frustration. I'm going to post my code so future google searchers can see the answer:

styles/fonts.ts:

import localFont from 'next/font/local'

const dempsey = localFont({
  display: 'swap',
  variable: '--font-dempsey',
  src: '../public/fonts/dempsey/dempsey-regular.woff2',
  weight: '400', // font-semibold
  style: 'normal',
})

const gilroy = localFont({
  src: [
    // SemiBold (600)
    {
      path: '../public/fonts/gilroy/gilroy-bold.woff2',
      weight: '600', 
      style: 'normal',
    },
    {
      path: '../public/fonts/gilroy/gilroy-bolditalic.woff2',
      weight: '600', 
      style: 'italic',
    },
    // // Bold (700)
    {
      path: '../public/fonts/gilroy/gilroy-extrabold.woff2',
      weight: '700', 
      style: 'normal',
    },
    {
      path: '../public/fonts/gilroy/gilroy-extrabolditalic.woff2',
      weight: '700', 
      style: 'italic',
    },
    // // ExtraBold (800)
    {
      path: '../public/fonts/gilroy/gilroy-black.woff2',
      weight: '800', 
      style: 'normal',
    },
    {
      path: '../public/fonts/gilroy/gilroy-blackitalic.woff2',
      weight: '800', 
      style: 'italic',
    },
  ],
  variable: '--font-gilroy',
})

export { dempsey, gilroy }


tailwind.config.js:

/** @type {import('tailwindcss').Config} */

module.exports = {
  content: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
  theme: {
    fontFamily: {
      gilroy: ['var(--font-gilroy)'], //NOTE: I couldn't get it to load fallback fonts in the array
      dempsey: ['var(--font-dempsey)'],
    },
    },
    extend: {},
  }},
}
_app.tsx:
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
import '@styles/fonts'
import '@styles/globals.css'
import '@styles/typography.css'

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout}

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page)
  return (
    <>
      {getLayout(<Component {...pageProps} />)}
    </>
  )
}

_document.tsx:
import { Html, Head, Main, NextScript } from 'next/document'
import { dempsey, poppins, gilroy } from '@styles/fonts'
const MyDocument = () => {
  return (
    <Html lang='en-US' className={`${dempsey.variable} ${gilroy.variable}`}>
      <Head></Head>
      <body className={`px-4 bg-egg max-w-screen overflow-x-hidden`}>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

export default MyDocument
styles/typography.css:
@tailwind utilities;
@layer utilities {
  html {
    @apply font-gilroy;
  }
  h1 {
    @apply font-gilroy text-8xl;
  }
  h2 {
    @apply font-dempsey text-6xl font-extrabold  text-peach my-8;
  }
Great black waspOP
Update: I can get it to work in development but the build fails in production. It doesn't like the path "../public/fonts/gilroy/..."
Great black waspOP
Update three hours later. Still no luck. Everything works great in dev but I get Module not found: Can't resolve '../public/fonts/gilroy/gilroy-bolditalic.woff2' in production. @English Lop when you get back on, could you maybe toss some suggestions over to me?
English Lop
@Great black wasp Hi, I'm back, first tested builded version, and css variables was missing in builded version, find workaround, but seems you facing other problem? Missing font file? How you build your project and starting in production?
English Lop
Try remove fonts imports and Html classNames from _document.tsx and import fonts only in _app.tsx:
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
import { dempsey, gilroy } from '@styles/fonts'
import '@styles/globals.css'
import '@styles/typography.css'

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout}

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page)
  return (
    <>
      <style jsx global>{`
        :root {
          --font-gilroy: ${gilroy.style.fontFamily};
          --font-dempsey: ${dempsey.style.fontFamily};
        }
      `}
      </style>
      {getLayout(<Component {...pageProps} />)}
    </>
  )
}