Font family theme styles not working with Next.js + MUI
See original GitHub issueDuplicates
- I have searched the existing issues
Latest version
- I have tested the latest version
Current behavior 😯
I’ve been trying to track down why theme font overrides don’t appear to be working for me – I’m not even sure if this is Next or MUI that’s causing the problem, but the behaviour is as described below. I’ve found a couple issues that cover similar issues, but all the solutions suggest using overrides
in the theme declaration, a property that appears to no longer exist in V5.
Problem:
All my <Typography />
blocks, irrespective of variant, are still defaulting to using Robot, Helvetica, Arial, sans-serif
fonts. The overrides I’ve declared are in the CSS hierarchy, but get overridden by variant-specific styles. Take for example, a body1
typography block that renders:
<p class="MuiTypography-root MuiTypography-body1 css-1nmo5nr-MuiTypography-root">My text</p>
The styles that apply, in reverse hierarchical order are:
.MuiTypography-body1 {
font-size: 1rem;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-weight: 400;
line-height: 1.5;
letter-spacing: 0.00938em;
}
MuiTypography-root {
margin: 0;
}
.css-1nmo5nr-MuiTypography-root {
margin: 0;
font-weight: 400;
font-family: Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Arial,sans-serif; /* <-- Here's the font I'm trying to apply */
font-size: 1rem;
line-height: 1.5;
font-weight: 700!important;
}
So you can see that the MuiTypography-body1
style is taking precedence here.
Theme
I’m correctly wrapping my app in a ThemeProvider block like so (I know it’s working because all other theme properties work, and Lato does work for Buttons and other elements, as well as colors and overrides):
...
import { ThemeProvider } from "@mui/material/styles";
import myTheme from "../theme/appTheme";
import CssBaseline from "@mui/material/CssBaseline";
function MyApp({ Component, emotionCache = clientSideEmotionCache, pageProps }) {
return (
<React.StrictMode>
<UserProvider>
<CacheProvider value={emotionCache}>
<ThemeProvider theme={myTheme}>
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
</UserProvider>
</React.StrictMode>
);
}
And my theme looks like this (some stuff removed for brevity, but all to do with custom button variants).
import {
createTheme,
responsiveFontSizes,
Theme,
alpha,
darken,
lighten } from "@mui/material/styles";
import { red, grey } from '@mui/material/colors';
declare module "@mui/material/styles" {
interface Palette {
base: any;
}
interface PaletteOptions {
base: any;
}
}
declare module "@mui/material/Button" {
interface ButtonPropsVariantOverrides {
principal: true;
}
}
const PRIMARY_MAIN = "#666";
const PRIMARY_LIGHT = #aaa;
const PRIMARY_DARK = "#111";
const WHITE = "#FFFFFF";
const FONT_FAMILY = [
"Lato",
"-apple-system",
"BlinkMacSystemFont",
'"Segoe UI"',
"Arial",
"sans-serif",
].join(",")
// Create a theme instance.
let myTheme: Theme = createTheme({
palette: {
primary: {
main: PRIMARY_MAIN,
light: PRIMARY_LIGHT,
dark: PRIMARY_DARK,
contrastText: "#fff",
},
secondary: {
main: grey["900"],
},
base: {
main: grey["100"],
dark: grey["300"],
},
error: {
main: red["A400"],
},
},
typography: {
fontFamily: FONT_FAMILY, // <-- According to docs, this should be working?
fontWeightRegular: 500,
h1: {
fontWeight: 700,
fontSize: "4rem",
"@media (max-width:375px)": {
fontSize: "2.5rem",
},
},
h2: {
fontWeight: 700,
fontSize: "3.2rem",
},
h3: {
fontWeight: 700,
},
h4: {
"@media (max-width:375px)": {
fontSize: "1.2rem",
},
},
body1: {
fontWeight: 400,
},
},
components: {
MuiCssBaseline: {
styleOverrides: {
html: {
overflowX: "hidden",
},
body: {
overflowX: "hidden",
},
// ^ Also tried @font-face, @global: { @font-face } here
},
},
MuiButton: {
styleOverrides: {
root: {
fontWeight: 700,
lineHeight: 2,
letterSpacing: 0.3,
textTransform: "none",
fontSize: "1rem",
borderRadius: 5,
whiteSpace: "nowrap",
padding: "0.2rem 1.2rem 0.3rem",
},
text: {
"&:active": {
backgroundColor: PRIMARY_LIGHT,
},
},
},
},
},
});
export default responsiveFontSizes(myTheme);
#10552 was the closest I could find to the issue, but the solution proposed is:
const theme = createMuiTheme({
typography: {
fontFamily: "Product Sans",
},
overrides: {
MuiTypography: {
body1: {
color: purple[500],
},
subheading: {
color: purple[500],
},
}
}
});
…which I’ve already tried, and also overrides
is not valid according to ESLint (TypeScript) so I suspect that’s V4 syntax?
The only lead I have is that I’m using Next’s font loading by adding a <style>
tag to the document instead of loading using @font-face inside the MUI theme – this seems to be the Next-recommended way of loading CDN fonts. I don’t think the order the font is loading is the problem though, because it does work for Buttons and anything that isn’t in a <Typography>
block.
...
<Head>
<title key="title">{title}</title>
<meta name="description" content={description} key="description" />
<link
href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,400;1,700;1,900&family=Oxygen+Mono&display=swap"
rel="stylesheet"
/>
<link rel="icon" href={favicon} />
</Head>
...
Also worth noting that in order for any styles applied in the overriding style block (.MuiTypography-body1
), I have to use !important, even when using sx
. For example:
<Typography
fontWeight='700 !important'
sx={{
fontSize: '1.1rem !important',
}}
>Some text</Typography>
Expected behavior 🤔
Typography should correctly handle the global style and inherit from the font family declared in the typography
object of custom themes.
Steps to reproduce 🕹
(See details from problem statement – simply create a custom theme with the details above and wrap a Next.js app in <ThemeProvider>
.
Context 🔦
Currently I have to use !important
to override the font styles, which means I need to use !important underneath for any local overrides.
Your environment 🌎
`npx @mui/envinfo`
System:
OS: macOS 12.1, M1 Max
Binaries:
Node: 17.3.1 - /opt/homebrew/bin/node
Yarn: 1.22.17 - /opt/homebrew/bin/yarn
npm: 8.4.1 - /opt/homebrew/bin/npm
Browsers:
Chrome: 98.0.4758.80 (Official Build) (arm64)
npmPackages:
@emotion/react: ^11.7.1 => 11.7.1
@emotion/styled: ^11.6.0 => 11.6.0
@mui/base: 5.0.0-alpha.64
@mui/icons-material: ^5.2.5 => 5.2.5
@mui/material: ^5.2.7 => 5.2.8
@mui/private-theming: 5.2.3
@mui/styled-engine: 5.2.6
@mui/system: 5.2.8
@mui/types: 7.1.0
@mui/utils: 5.2.3
@types/react: ^17.0.38 => 17.0.38
react: ^17.0.2 => 17.0.2
react-dom: ^17.0.2 => 17.0.2
typescript: ^4.5.4 => 4.5.4
Issue Analytics
- State:
- Created 2 years ago
- Comments:8 (3 by maintainers)
Top GitHub Comments
I’m having the same issue and I’m using v5. I have created a sandbox to reproduce this in a minimal example: codesandbox. Or maybe I have made a mistake, what I’ve done there is based on this page of the documentation. Will you please have a look @mnajdova ?
UPDATE: No problem anymore, it works now. Here are the important mistakes I’d made: 1. I hadn’t used CssBaseline. I thought it was optional like using CSS reset! 2. I missed a comma between
local('Nunito')
andurl(${Nunito}) format('woff)
insrc
part.I can’t believe I missed this reply, thank you so much!