Transfer the @font-face declaration from the global CSS file into the MUI Theme

In my project, I have an index.css file that includes the following @font-face declaration:

//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");
}
...

Additionally, I have two files named GlobalStyles.jsx and CustomThemeProvider.jsx which are used to create my MUI theme:

// 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;

While this setup works well for customizing the theme using window.xxx variables from a public config.js file, I am facing an issue with integrating the @font-face definition from index.css into the theme configuration. My goal is to use variables to specify the font links in the theme, making it easier to white-label fonts when rebuilding the application.

I would appreciate any insights or suggestions on how to accomplish this task effectively without using CSSBaseline in our current implementation. Thank you!

Answer №1

To implement custom fonts in your MUI theme, you can define font URLs as theme variables and then use them in the @font-face declaration. Finally, import and apply the @font-face styles within your MUI theme.

Here is an 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,
    },
  },
  // Define 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;

Answer №2

Assign the font URLs to variables within your CustomThemeProvider.jsx file or in a separate configuration file, such as fontConfig.js.

// fontConfig.js

const fontPaths = {
  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",
};

export default fontPaths;
  1. Include the fontPaths object into your CustomThemeProvider.jsx file.
// CustomThemeProvider.jsx
import React from "react";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import fontPaths from "./fontConfig"; // Import the fontPaths object

export const appTheme = createTheme({
  // ... Your current theme settings ...

  // Incorporate the font URLs using the imported fontPaths object
  typography: {
    // ... Your existing typography setup ...

    fontFamily: `-apple-system, ${window.theme.fonts.fontFamilyName}, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif`,
  },
  overrides: {
    MuiCssBaseline: {
      // Define the font URLs as variables
      "@font-face": {
        fontFamily: "My Font",
        fontDisplay: "swap",
        fontWeight: 400,
        src: `
          url(${fontPaths.eot}) format("embedded-opentype"),
          url(${fontPaths.woff2}) format("woff2"),
          url(${fontPaths.woff}) format("woff"),
          url(${fontPaths.ttf}) format("truetype"),
          url(${fontPaths.svg}) format("svg");
        `,
      },
    },
  },
});

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

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

export default CustomThemeProvider;

By following these instructions, you have organized the @font-face declaration within your MUI theme setup for easier management and customization.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to test routing with Next JS using links?

As a newcomer to the NextJS environment and currently in the process of migrating an application from standard ReactJS, I am faced with a challenge regarding testing a link to another page. Can anyone provide some guidance on how I should refactor my test ...

Emphasize specific letters in a word by making them bold, according to the user

In my app, there is a search feature that filters data based on user input and displays a list of matching results. I am trying to make the text that was searched by the user appear bold in the filtered data. For example, if the user searches 'Jo&apos ...

Next.js users have reported experiencing style flickering when utilizing material-ui's useMediaQuery feature upon initial rendering

Encountering style flickering on initial render in Next.js while using the @mui/material/useMediaQuery function. The issue arises from the useMediaQuery value changing between server side and client side rendering. Is there a solution to this problem? imp ...

The React application in VS Code crashes unexpectedly when using the Chrome debugger

Currently, I am facing a challenge while trying to debug a React application using VS Code along with the Chrome debugger extension on my Windows 10 x64 system. Whenever I attempt to log into the application from the login page, the debugger browser unexp ...

Align navigation bar using Angular Material

Trying to center my navbar has been a struggle for me. I attempted using 'layout-align='space-between center' but it's not taking up 100% width and is acting more like an inline element. I've been following the documentation close ...

What steps can I take to limit access to my API exclusively for the Frontend?

I'm in the process of creating a gaming platform, and unfortunately, there has been an exploitation of the API. How can I establish a set of "approved domains" that are allowed to access my API? The previous misuse of the API resulted in individuals ...

Using nextJS to establish a context within a Server Component and incorporating a new library

I attempted to incorporate Framer Motion into my project, but when I added it, an error occurred. The error message displayed was: TypeError: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Fo ...

Having trouble getting a DIV to appear on top of another DIV containing an image

I need help with positioning an "InfoBox" above the main header image on my website. Despite trying z-indexes and adjusting position, I can't seem to get it right. If anyone has any suggestions, please share. Thank you! For reference, here is the HTM ...

The functionality of Google Maps code is limited on Android devices because the map feature is not available

After updating the Google Maps embed code to be responsive for mobile devices, I discovered that the map still won't display on Android or iPhone. The following is the modified code. Can anyone assist me in resolving this issue so that the map can sho ...

Developing an international loading animation with the power of React and Redux

I am looking to create a reusable spinner but unsure of the best approach. After trying out two methods, I feel like I need some guidance as I am still new to React. Method 1: MyComponent.js const MyComponent = (props) => { ... return ( ...

Proper Alignment of Div Elements

Just starting out with coding and currently practicing display and positioning. I've created a webpage with multiple divs containing the same content, displayed in a vertical scroll order. Now, I'm looking to position these divs side by side in r ...

New feature that allows color change to be black or white depending on background color

Can anyone suggest a function from material UI that can automatically change text color to either white or black based on the background color? For example: <AppBar color="primary"> <Toolbar> <Typography color="i ...

Increase the spacing within div columns containing rows of uniform height

Is there a way to add some extra space between the H3-1 div and the H3-2 div? Ideally, I would like to achieve this without using custom CSS, but if necessary, that's okay too. I'd prefer to stick with the col-sm-6 class instead of using col-sm ...

The top margin is experiencing issues and is not functioning correctly

I'm struggling to identify the problem with this script: http://jsfiddle.net/AKB3d/ #second { margin-top:50px; ... } My goal is to have the yellow box positioned 50px below the top border of the right box. However, every time I add margin-top to ...

Rearranging the grid table in ag-grid by relocating a newly visible column to the bottom

Seeking a solution for organizing newly added columns in a React app using ag-grid version 28.1.1. Currently, the columns are automatically sorted alphabetically upon addition from the Columns toolpanel. Is there a way to move a new column to the end of th ...

Looking to add a dynamic divider between two columns that can be adjusted in width by moving the mouse left and right?

If you're looking for an example of two columns adjusting their width based on mouse movement, check out this page from W3Schools. I'm trying to implement this feature in my React app, but I'm unsure of how to proceed. Below is the JSX code ...

The issue of focus being lost with HOC and Formik

In my latest project, I developed a bootstrap form input component that utilizes HOC (Higher Order Component) to change an icon upon submission. The input validation is done through the Formik library. <InputUi placeholder="Enter your email" ...

Unexpected output from Material UI Textfield

When attempting to print a page of my React app using window.print(), everything prints correctly except for the Textfield component from Material UI. It works fine when there are only a few lines of text, but when there is a lot of text, it appears like t ...

React Bootstrap - Problem with OverlayTrigger Tooltip positioning

I'm having trouble implementing a basic Tooltip that appears when hovering over a div element. However, the tooltip is displaying in the wrong position despite my attempts to correct it. I am currently utilizing react-bootstrap version 2.4.0. Here is ...

Tips for extracting a keyword or parameters from a URL

I'm in the process of creating my personal website and I am interested in extracting keywords or parameters from the URL. As an illustration, if I were to search for "Nike" on my website, the URL would transform into http://localhost:3000/searched/Nik ...