Skip to content

Instantly share code, notes, and snippets.

@knowler
Last active February 21, 2024 17:03
Show Gist options
  • Save knowler/d74f1cdfa0d80a63910b554998eec112 to your computer and use it in GitHub Desktop.
Save knowler/d74f1cdfa0d80a63910b554998eec112 to your computer and use it in GitHub Desktop.
Fontsource with Remix (pre-1.7.3)

Fontsource with Remix

Fontsource is designed to work with projects that bundle their CSS. You import their stylesheet and the bundler will place the fonts in your build directory and the CSS file will have the correct URL for the @font-face src.

Remix doesn’t bundle CSS and so while you can import their CSS file and add it to your links, the URL to font will be incorrect. It is still possible to use Fontsource with Remix. We just need to create our own @font-face declaration with the correct URL to the font (ideally, one that benefits from Remix’s asset fingerprinting). There’s a bit of manual set up, but once that’s done, you can serve the font on your site and benefit from updates for the font.

  1. Install your font:
    npm install --save @fontsource/montserrat
  2. Create a directory for fonts in your the app directory so that you can fingerprint the font assets for long term caching. Run the following from your project root.
    mkdir app/fonts
  3. Link the files directory of the font to the your app/fonts directory. Run the following from your project root.
    ln -s node_modules/@fontsource/montserrat/files app/fonts/montserrat
  4. In the layout that you need the font, import the font file you want. It’s a sym-link so autocomplete won’t work unfortunately.
    import montserratVariableFontLatin from '~/fonts/montserrat/montserrat-latin-variable-wghtOnly-normal.woff2`;
  5. Define the @font-face using the font asset URL that we imported. We have to use a <style> element to include this as we cannot set the URL as a custom property since they cannot be accessed in @font-face declarations. Take a look at the corresponding CSS file in the @fontsource Node module to know what to set here (especially for the unicode-range and font-weight).
    const montserratFontFaceDeclaration = `
      @font-face {
        font-family: 'Montserrat', sans-serif;
        font-style: normal;
        font-display: swap;
        font-weight: 100 900;
        src: url(${montserratVariableFontLatin}) format('woff2');
        unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
      }
    `;
    <head>
      <style dangerouslySetInnerHTML={{__html: montserratFontFaceDeclaration}} />
    </head>
@jgentes
Copy link

jgentes commented Oct 25, 2022

Hmm, or just do this:

const links: LinksFunction = () => [
  {
    rel: 'stylesheet',
    href: 'http://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400&family=Public+Sans:wght@300;400;500;700&display=swap',
  },
]

@knowler
Copy link
Author

knowler commented Oct 25, 2022

@jgentes Fontsource is a tool for self-hosting open source fonts like Google Fonts. Your method is definitely simple and works for someone who doesn’t care about self-hosting their fonts, but it’s not really relevant.

@jgentes
Copy link

jgentes commented Oct 25, 2022

I see, yes it would be nice if there were a way to just reference a local font file in a similar fashion to a web font.

@sergiodevelops
Copy link

@jondcallahan
Copy link

FYI this is no longer needed as of Remix 1.7.3 https://github.com/remix-run/remix/releases/tag/remix%401.7.3 - Thanks to @KingSora 🎉

@jondcallahan
Copy link

import FontStyles from '@fontsource/MyFontName/index.css';

const links: LinksFunction = () => [
  {
    rel: 'stylesheet',
    href: FontStyles,
  },
]

@ayuhito
Copy link

ayuhito commented Nov 16, 2022

import FontStyles from '@fontsource/MyFontName/index.css';

const links: LinksFunction = () => [
  {
    rel: 'stylesheet',
    href: FontStyles,
  },
]

When multiple fonts and weights are considered, each import creates its own stylesheet which could mean you'll be loading multiple stylesheets for each variant. Not sure if that is ideal behaviour and if there's a possible workaround for that.

@jgentes
Copy link

jgentes commented Nov 18, 2022

Thanks for the tip @jondcallahan - I can confirm that works!

@nikitapashinsky
Copy link

Thank you so much for this ❤️

@ammar-oker
Copy link

consider the following solution if you have bunch of css imports across the project,

// root.tsx
import { cssBundleHref } from '@remix-run/css-bundle';
import { LinksFunction } from '@remix-run/server-runtime';

import '@fontsource/lato/index.css';
import 'another-external-file.css'

export const links: LinksFunction = () => [
  ...(cssBundleHref ? [{ rel: 'stylesheet', href: cssBundleHref }] : []),
];

simply import any css file anywhere and it'll be added to your bundle :)

@Skoob1905
Copy link

Any help with this !! None of the solutions here are working for me :/

@jondcallahan
Copy link

@Skoob1905 If you're using remix as a vite plugin then you can just

// root.tsx
import "@fontsource-variable/inter";

@ayuhito
Copy link

ayuhito commented Feb 21, 2024

Any help with this !! None of the solutions here are working for me :/

There's an official guide too: https://fontsource.org/docs/guides/remix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment