Is it possible to 'nest' themes in React?

I have a React app which uses the Material UI Theme Provider to set the font throughout, like this:

App.js

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        ... routes rendering various elements ...
      </Routes>
    </BrowserRouter>
  );
};

const ThemedApp = () => {
  const theme = createTheme({
    palette: {
      primary: {
        main: Colours.primaryColor,
      },
      secondary: {
        main: Colours.secondaryColor,
      },
    },
    typography: {
      fontFamily: 'serif',
      fontSize: 16,
    },
  });
  return (
    <ThemeProvider theme={theme}>
      <App />
    </ThemeProvider>
  );
};

const FirebaseApp = () => {
  return <ThemedApp />;
};

export default FirebaseApp;

(I didn’t write this code, so I’m not sure why it exports ThemedApp as FirebaseApp instead of just renaming ThemedApp to FirebaseApp or something, but that’s a different issue).

However, one section of the app (we’ll call it ‘DifferentFontArea’) needs to use a different font, but the rest of the theme is the same. I’ve tried ‘nesting’ the ThemeProvider like this (this component is a child of the App component shown above, and therefor wrapped within ThemeProvider):

const DifferentFontBase = () => {

    return (
      <>
        ... component details go here
      </>
    );
  }

};

const DifferentFontArea = () => {
  const theme = useTheme();
  const fontTheme = createTheme({
    ...theme,
    typography: {
      fontFamily: 'sans-serif',
    },
  });
  return (
    <ThemeProvider theme={fontTheme}>
      <DifferentFontBase />
    </ThemeProvider>
  );
};

export default DifferentFontArea;

This seems to work; when DifferentArea is rendered, it has a sans-serif font, whereas the rest of the app has the serif font. I’m just not sure whether it’s ok to nest providers like this, as I can’t find references to it in the documentation.

>Solution :

Components will use the closest provider for any context they are referencing. This means the theme created in ThemedApp is not visible, in any sense of the word, to the components inside <DifferentFontBase />, as all the components inside will be referencing the value from closer provider, i.e. fontTheme.

Whether it’s okay or not depends on your use case. It seems that, in the scenario you posted, since fontTheme references the original theme, you should be okay.

Leave a Reply