Can't import Google Fonts with Styled Components and Next.js

Viewed 13876

I'm having the following issue when trying to load Google Fonts. I read that I'm supposed to write something like this in _document.js to import it inside a head tag

import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          <link
            rel="preload"
            href="/fonts/noto-sans-v9-latin-regular.woff2"
            as="font"
            crossOrigin=""
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}
export default MyDocument;

but this is the code I had to use to make Styled Components work with Next.js

import Document, { DocumentContext } from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

So my question is: how can I modify my _document.js file to use the styles of Google Fonts?

Also, if it's of any help, this is the GlobalStyle I'm using and that doesn't import the fonts

import { createGlobalStyle } from '@xstyled/styled-components';

const GlobalStyle = createGlobalStyle`

@import url('https://fonts.googleapis.com/css2?family=Lato&family=Rubik&display=swap');

* {
    margin: 0;
    padding: 0;
}

*,
*::before,
*::after {
    box-sizing: inherit;
}

html {
    box-sizing: border-box;
    font-size: 62.5%; 
    position: relative;
    background: grey;
}

body {
  font-family: 'Lato', sans-serif;
}
`;

const BasicLayout = ({ children }: { children: any }) => {
  return (
    <>
      <GlobalStyle />
      {children}
    </>
  );
};

export default BasicLayout;
2 Answers

Head to this page.

https://nextjs.org/docs/advanced-features/custom-app

Please read about custom _app.js and then do as following:

First, You need to create a custom _app.js for your app. (This must be in the root of your pages directory)

Then you need to create _app.css in the same directory

Then import the css file into your _app.js

import "./_app.css";

Then in your _app.css file, import your google font like the following:

@import url("https://fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700&display=swap");

in the css file and in the body tag add the following line:

body {
  font-family: "PT Sans Narrow", sans-serif;
  etc..
}

I came across the same issue, but wasn't a fun of Hooman's answer as that requires the need of having a .css file only to contain the google font import.

Instead, here's the proper way to load your fonts while using styled-components:

import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
  DocumentInitialProps,
} from "next/document";
import { ServerStyleSheet } from "styled-components";

class MyDocument extends Document {
  // Load styles before rendering
  static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render() {
    return (
      <Html lang="en">
        <Head>
          {/* Google Fonts */}
          <link rel="preconnect" href="https://fonts.googleapis.com" />
          <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
          <link
            href="https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@400;500&display=swap"
            rel="stylesheet"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

Make sure your render method is not defined as static.

Related