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

Saving the previous component's DOM in a React application

Understanding the Root.js File const Root = () => ( <HashRouter> <div> <Route exact path="/" component={Main}/> <Route path="/main/:page" component={Main}/> <Route path="/detail ...

Leverage the exported data from Highcharts Editor to create a fresh React chart

I am currently working on implementing the following workflow Create a chart using the Highcharts Editor tool Export the JSON object from the Editor that represents the chart Utilize the exported JSON to render a new chart After creating a chart through ...

I'm curious if it's doable to include a tooltip that appears when hovering the mouse cursor over the chosen element in the input for Autocomplete MUI

Can a tooltip be added to an element inside an input when the element is wider than the container and the mouse cursor hovers over it? I attempted to use a Tooltip around a TextField in the renderInput attribute. While this method works, there seems to b ...

A guide on implementing Increment and Decrement functionalities in ReactJS with the help of Formik

I am currently facing a straightforward issue with incrementing and decrementing the value in my TextField component. My project is built using Formik and Material UI within React. For more details, please check out this CodeSandbox link: VIEW HERE <T ...

Beware: Inaccessible code detected in Reactjs usage

Currently, I am working on a ReactJS project where I have integrated two components - PrescriptionIndex and PrescriptionNew. Let's start with the 'PrescriptionNew' component: import React, { Component } from 'react'; import Flo ...

State does not reflect modifications made in TinyMCE within my React Component

Hey there! I am currently exploring the use of TinyMCE with React and State. Below you can find the React component that I have been working on. Upon loading, this component displays the initial text passed into it through props. However, despite making ...

What safety measures should be implemented when granting users permission to modify HTML and CSS on your site?

I'm really impressed by the customization options on Tumblr. Users can edit the HTML and CSS of their profiles, which is something I'd love to incorporate into my own site. However, I'm concerned about the security implications of allowing t ...

producing a NaN result when calling a reducer with an integer value

Could anyone assist me with this react-redux code? I have an input field that accepts numbers and adds them to the counter above. My goal is to reset the counter to 0 if the input is not a number, but currently when I type any character other than an int ...

Tips for adjusting the dimensions of a child element to match its parent in Angular 12 with Typescript

I have included the child component in the parent component and I am displaying that child component within a col-md-8. What I want to achieve is to highlight a specific div in the child component with additional text, making it equal in size to the parent ...

Display a universal loading screen on all React.js pages when making calls from various locations

As I was working on adding a global loading screen for data fetched from an API, I came across this helpful answer and decided to implement something similar. LoadingProvider.js import { createContext, useContext, useState } from "react"; const ...

The utilization of Display Flex resulting in the enlargement of the containing div

I am currently learning CSS and trying out some new things. I am looking to create a page with two side-by-side divs: one for the sidebar and the other for the main content. My goal is to have the sidebar take up 400px of width and allow the content part t ...

Guide to triggering React Material-UI modal and filling it with data from an Ajax request when a button is clicked

Despite my efforts to find a similar question, I couldn't come across one. My apologies if I overlooked it. Currently, I am working on a React Material-UI project to develop a basic web application. Within this application, there is an XGrid that disp ...

Creating a Scrollable React Form Group

Struggling to display a large amount of data that is not scrollable, how can I make this form group scrollable to easily view all the data? render() { return ( <div style={{width: '50rem', margin: '1rem&ap ...

Bringing in a created class establishes the universal prototype

When working with the given react component, I noticed something interesting. Even after importing it into multiple components and calling the increment method, it seems to manipulate the same instance rather than creating separate instances. This behavior ...

Animating a div's width with CSS from left to right

My goal is to create an animation effect for two overlapping divs that will reveal or hide the text inside them. I want one div to animate from left to right while the other animates from right to left, creating a wiping effect where as one piece of text d ...

Can an image be allowed to overflow outside of a div without changing the div's size?

Starting Point I am in the process of designing a layout with Bootstrap 4. Here's a rough representation of what I am aiming for: https://i.sstatic.net/7QTpk.jpg And here is the basic structure: <div class="row"> <div class="col-12 c ...

Creating and sending an email using a contact form in Create-React-App

Currently, I am in the process of developing a website using create-react-app from GitHub. My next task is to create a contact page where user information will be submitted and sent to a designated email address. However, my lack of experience with back-e ...

Nextjs compatibility with React slick

For my upcoming project in Next.js, I'm considering incorporating the React-slick library for an image slider. However, I've encountered a problem during the installation process. I attempted to install "react-slick" and "slick-carousel" as outl ...

What are some potential causes of webpack-dev-server's hot reload feature not working properly?

Having an issue with my React project. When I try to use hot reload by running "npm start" or "yarn start" with webpack-dev-server configured (--hot flag), I'm getting the error message: [error message here]. Can anyone assist me in troubleshooting th ...

What could be the reason for the unexpected occurrence of my CSS rule application?

In my collection of CSS files, I have a specific class defined in the common CSS file: common.css .container-example { display: grid; height: 100%; width: 100%; background-color: black; } .container-example > div { overflow: hidden; } This ...