React hook to load fonts

Posted on 2022-06-11 in Trucs et astuces Last modified on: 2023-08-01

If you need to load a specific font in a component, you can use this hook. It will return true when the fonts are loaded. It relies on the document.fonts API to load the fonts. If the fonts are already loaded, the promise will be fulfilled immediately and the component should be "immediately" re-rendered.

import { useEffect, useState } from "react";

export const useFonts = (...fontNames: string[]) => {
  const [isLoaded, setIsLoaded] = useState(false);

  useEffect(() => {
    Promise.all(fontNames.map(
      (fontName) => document.fonts.load(`16px "${fontName}"`)
    )).then(() => {
      setIsLoaded(true);
    });
  }, [fontNames]);

  return isLoaded;
};

Example usage:

const areFontsLoaded = useFonts("Mistral", "Freestyle Script");

if (!areFontsLoaded) {
  return <Loader />;
}

Note

We don't need to check that the API is supported with document && document.fonts since all browsers support it nowadays. See here.

As pointed out by choyeK, for testing you may want to mock this with:

Object.defineProperty(document, 'fonts', {
  value: { load: Promise.resolve({}) },
})