cssreactjsmaterial-uifontsfont-face

Move @font-face declaration from global CSS into MUI Theme


I have the below index.css file:

//Index.css
...
@font-face {
  font-family: "My Font";
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url(/public/fonts/my-font.eot);
  src: url(/public/fonts/my-font.eot#iefix) format("embedded-opentype"),
    url(/public/fonts/my-font.otf) format("otf"),
    url(/public/fonts/my-font.svg) format("svg"),
    url(/public/fonts/my-font.woff) format("woff"),
    url(/public/fonts/my-font.woff2) format("woff2");
}
...

Then I have both GlobalStyles.jsx & CustomThemeProvider.jsx files for creating my MUI theme, as below:

// GlobalStyles.jsx
import GlobalStyles from "@mui/material/GlobalStyles";

const importGlobalStyles = (
  <GlobalStyles
    styles={{
      body: {
        backgroundImage: `url(${window.theme.backgroundLink})`,
        backgroundColor: `${window.theme.colors.pageBackground}`,
        color: `${window.theme.colors.font}`,
        fontFamily: `-apple-system, ${window.theme.fontFamilyName}, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
        "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;`,
      },
    }}
  />
);

export default importGlobalStyles;

And

//CustomeThemeProvider.jsx

import React from "react";
import { createTheme, ThemeProvider } from "@mui/material/styles";

export const appTheme = createTheme({
  palette: {
    primary: {
      main: window.theme.colors.primary,
    },
    error: {
      main: window.theme.colors.error,
    },
  },
typography: {
    allVariants: {
      fontFamily: `-apple-system, ${window.theme.fonts.fontFamilyName}, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif`,
    },
    fontFamily: `-apple-system, ${window.theme.fonts.fontFamilyName}, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif`,
    h1: {
      fontWeight: 500,
      fontSize: "30pt",
      lineHeight: "40pt",
      color: window.theme.colors.primary,
    },
},
});

const CustomThemeProvider = (props) => {
  const { children } = props;

  return <ThemeProvider theme={appTheme}>{children}</ThemeProvider>;
};

export default CustomThemeProvider;

This all works fine, allowing me to customize the theme by setting window.xxx theme variables in a public config.js file, which I can then pass into the theme (you can see them below passed in using window.theme.xxx).

The problem I have, is I can't figure out how to lift the @font-face from index.css and move it into the theme setup that I have, so I can set the theme links as variables to pass in. That way, I can white-label fonts when rebuilding this app, etc.

Any thoughts as to how best achieve this? I've read through MUI docs and haven't found anything super helpful. We don't use CSSBaseline, and don't particularly want to implement either as it's unnecessary in our current implementation. Any suggestions as to how to do this please?


Solution

  • You can Define font URLs as theme variables and then use the defined theme variables in the @font-face declaration and then Import and apply the @font-face styles within your MUI theme.

    For example -

    CustomThemeProvider.jsx:

    import React from "react";
    import { createTheme, ThemeProvider } from "@mui/material/styles";
    
    export const appTheme = createTheme({
      palette: {
        primary: {
          main: window.theme.colors.primary,
        },
        error: {
          main: window.theme.colors.error,
        },
      },
      typography: {
        allVariants: {
          fontFamily: `-apple-system, ${window.theme.fonts.fontFamilyName}, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif`,
        },
        fontFamily: `-apple-system, ${window.theme.fonts.fontFamilyName}, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif`,
        h1: {
          fontWeight: 500,
          fontSize: "30pt",
          lineHeight: "40pt",
          color: window.theme.colors.primary,
        },
      },
      // Add font URLs as theme variables
      fonts: {
        myFont: {
          eot: "/public/fonts/my-font.eot",
          otf: "/public/fonts/my-font.otf",
          svg: "/public/fonts/my-font.svg",
          woff: "/public/fonts/my-font.woff",
          woff2: "/public/fonts/my-font.woff2",
        },
      },
    });
    
    const CustomThemeProvider = (props) => {
      const { children } = props;
    
      return <ThemeProvider theme={appTheme}>{children}</ThemeProvider>;
    };
    
    export default CustomThemeProvider;
    

    GlobalStyles.jsx

    import React from "react";
    import { GlobalStyles as MuiGlobalStyles } from "@mui/material";
    import { appTheme } from "./CustomThemeProvider";
    
    const GlobalStyles = (
      <MuiGlobalStyles
        styles={{
          body: {
            backgroundImage: `url(${window.theme.backgroundLink})`,
            backgroundColor: `${window.theme.colors.pageBackground}`,
            color: `${window.theme.colors.font}`,
            fontFamily: appTheme.typography.allVariants.fontFamily,
            // Other styles...
          },
          // Add @font-face styles using theme variables
          '@font-face': {
            fontFamily: 'My Font',
            fontStyle: 'normal',
            fontDisplay: 'swap',
            fontWeight: 400,
            src: `
              url(${appTheme.fonts.myFont.eot}),
              url(${appTheme.fonts.myFont.eot}#iefix) format("embedded-opentype"),
              url(${appTheme.fonts.myFont.otf}) format("otf"),
              url(${appTheme.fonts.myFont.svg}) format("svg"),
              url(${appTheme.fonts.myFont.woff}) format("woff"),
              url(${appTheme.fonts.myFont.woff2}) format("woff2")
            `,
          },
        }}
      />
    );
    
    export default GlobalStyles;