Theming

Jumbo React Next uses MUI v7 with Emotion for CSS-in-JS styling. The @jumbo framework extends standard MUI theming with four independent region themes (main, header, sidebar, footer), each supporting three modes (light, semi-dark, dark). Runtime theme switching is provided by the CustomizerSettings drawer.

Theme regions

Splitting the theme into four independent regions lets each area of the layout carry its own color scheme. A common pattern is a dark sidebar with a light main content area:

RegionControlsFiles
MainPage background, typography, primary/secondary palettesrc/themes/main/
HeaderApp bar background, text colorssrc/themes/header/
SidebarSidebar drawer background, nav item colorssrc/themes/sidebar/
FooterFooter background and textsrc/themes/footer/

Each region folder contains three mode files:

src/themes/
  main/
    default.ts    ← light
    dark.ts       ← dark
    semi-dark.ts  ← semi-dark (dark sidebar + light content)
  header/  sidebar/  footer/   (same structure)

Modifying colors

Open the token file for the region you want to change and edit the MUI createTheme object:

typescript
// src/themes/main/default.ts
import { createTheme } from '@mui/material/styles';
 
export const mainTheme = createTheme({
  palette: {
    mode: 'light',
    primary: {
      main:          '#7352C7',
      light:         '#9E86DB',
      dark:          '#3F1D9B',
      contrastText:  '#fff',
    },
    secondary: {
      main:          '#E44D26',
      contrastText:  '#fff',
    },
    background: {
      default: '#F5F7FA',
      paper:   '#FFFFFF',
    },
  },
  typography: {
    fontFamily: '"Noir Pro", "Roboto", "Helvetica", "Arial", sans-serif',
    h1: { fontSize: '2rem', fontWeight: 700 },
  },
  shape: {
    borderRadius: 8,
  },
});

Dark mode

Enable dark mode by swapping the main (and optionally the other region) themes to their dark variants. This is what Demo 4 does in src/components/Demo4Layout/themes/index.ts:

typescript
// src/components/Demo4Layout/themes/index.ts
import { mainThemeDark }    from '@/themes/main/dark';
import { headerThemeDark }  from '@/themes/header/dark';
import { sidebarThemeDark } from '@/themes/sidebar/dark';
import { footerThemeDark }  from '@/themes/footer/dark';
import { createJumboTheme } from '@jumbo/utilities/helpers';
 
export const CONFIG4 = {
  THEME: createJumboTheme(mainThemeDark, headerThemeDark, sidebarThemeDark, footerThemeDark),
};

To give your default layout a dark theme, update src/config/index.ts to import the dark files.

Runtime theme switching

The CustomizerSettings drawer lets users switch theme modes at runtime without a page reload. It is controlled by AppProvider context (src/components/AppProvider/AppProvider.tsx). The context stores the currently selected mode and region themes, and JumboTheme reads from it to re-render with the updated theme.

If you want to implement your own dark mode toggle:

tsx
'use client';
 
import { useJumboTheme } from '@jumbo/components/JumboTheme';
import { mainTheme }     from '@/themes/main/default';
import { mainThemeDark } from '@/themes/main/dark';
 
export function DarkModeToggle() {
  const { muiTheme, setMuiTheme } = useJumboTheme();
  const isDark = muiTheme.palette.mode === 'dark';
 
  return (
    <button onClick={() => setMuiTheme(isDark ? mainTheme : mainThemeDark)}>
      {isDark ? 'Light mode' : 'Dark mode'}
    </button>
  );
}

Styling components with sx

The MUI sx prop accepts any CSS property alongside theme tokens:

tsx
<Box
  sx={{
    bgcolor: 'primary.main',
    color:   'primary.contrastText',
    p:       3,
    borderRadius: 2,
    boxShadow: (theme) => theme.shadows[4],
  }}
>
  Content
</Box>

Emotion's styled API

Use @emotion/styled for component-level styles that need full CSS access:

typescript
import styled from '@emotion/styled';
import { Box } from '@mui/material';
 
export const PageWrapper = styled(Box)(({ theme }) => ({
  backgroundColor: theme.palette.background.default,
  minHeight: '100vh',
  padding: theme.spacing(3),
 
  [theme.breakpoints.down('md')]: {
    padding: theme.spacing(2),
  },
}));

AppRouterCacheProvider

The root layout wraps the entire tree in AppRouterCacheProvider from @mui/material-nextjs:

tsx
// src/app/[lang]/layout.tsx
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
 
export default async function RootLayout({ children }) {
  return (
    <html>
      <body>
        <AppRouterCacheProvider>
          <JumboTheme init={CONFIG.THEME}>
            {children}
          </JumboTheme>
        </AppRouterCacheProvider>
      </body>
    </html>
  );
}

This is required for MUI + Emotion to work correctly with Next.js Server Components. It ensures styles are collected during SSR and deduped on the client. See the Server Components guide for more details.