Application Theme
If you want to override some styles across the entire application, you can use a custom theme, leveraging the Material UI Theming support. Custom themes let you override colors, fonts, spacing, and even the style of individual components.
Using A Custom Theme
Pass a custom theme
to the <Admin>
component to override the style of the entire application:
import { Admin, defaultTheme } from 'react-admin';
import indigo from '@mui/material/colors/indigo';
import pink from '@mui/material/colors/pink';
import red from '@mui/material/colors/red';
const myTheme = {
...defaultTheme,
palette: {
primary: indigo,
secondary: pink,
error: red,
contrastThreshold: 3,
tonalOffset: 0.2,
},
typography: {
// Use the system font instead of the default Roboto font.
fontFamily: ['-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Arial', 'sans-serif'].join(','),
},
};
const App = () => (
<Admin theme={theme}>
// ...
</Admin>
);
Note that you don’t need to call Material-UI’s createTheme
yourself. React-admin will do it for you.
Theming Individual Components
In a custom theme, you can override the style of a component for the entire application using the components
key.
For instance, to create a custom theme that overrides the style of the <Datagrid>
component:
import { defaultTheme } from 'react-admin';
const theme = {
...defaultTheme,
components: {
...defaultTheme.components,
RaDatagrid: {
styleOverrides: {
root: {
backgroundColor: "Lavender",
"& .RaDatagrid-headerCell": {
backgroundColor: "MistyRose",
},
}
}
}
}
};
const App = () => (
<Admin theme={theme}>
// ...
</Admin>
);
There are 2 important gotchas here:
- Don’t forget to merge your custom style overrides with the ones from react-admin’s
defaultTheme
, otherwise the application will have the default Material UI theme (most notably, outlined text inputs) - Custom style overrides must live under a
root
key. Then, the style override syntax is the same as the one used for thesx
prop.
To guess the name of the subclass to use (like .RaDatagrid-headerCell
above) for customizing a component, you can use the developer tools of your browser, or check the react-admin documentation for individual components (e.g. the Datagrid CSS documentation).
Tip: As an alternative, you can also re-export styled components, and use them instead of the react-admin components. Check the Reusable Components documentation for an example.
Overriding Default Props
You can use this technique to override not only styles, but also defaults for components. That’s how react-admin applies the filled
variant to all TextField
components. So for instance, to change the variant to outlined
, create a custom theme as follows:
import { defaultTheme } from 'react-admin';
const theme = {
...defaultTheme,
components: {
...defaultTheme.components,
MuiTextField: {
defaultProps: {
variant: 'outlined',
},
},
MuiFormControl: {
defaultProps: {
variant: 'outlined',
},
},
}
};
Tip: TypeScript will be picky when overriding the variant
defaultProp
. To avoid compilation errors, type the variant
value as const
:
import { defaultTheme } from 'react-admin';
const theme = {
...defaultTheme,
components: {
...defaultTheme.components,
MuiTextField: {
defaultProps: {
variant: 'outlined' as const,
},
},
MuiFormControl: {
defaultProps: {
variant: 'outlined' as const,
},
},
}
};
Using A Dark Theme
React-admin ships two base themes: light and dark. To use the dark theme, import the darkTheme
and pass it as the <Admin theme>
prop:
import { darkTheme } from 'react-admin';
const App = () => (
<Admin theme={darkTheme} dataProvider={...}>
// ...
</Admin>
);
Alternatively, you can create a custom theme object with a mode: 'dark'
palette:
import { defaultTheme } from 'react-admin';
const darkTheme = {
...defaultTheme,
palette: { mode: 'dark' }
};
const App = () => (
<Admin theme={darkTheme} dataProvider={...}>
// ...
</Admin>
);
Letting Users Choose The Theme
It’s a common practice to support both a light theme and a dark theme in an application, and let users choose which one they prefer.
React-admin’s <Admin>
component accepts a darkTheme
prop in addition to the theme
prop.
import { Admin, defaultTheme } from 'react-admin';
const lightTheme = defaultTheme;
const darkTheme = { ...defaultTheme, palette: { mode: 'dark' } };
const App = () => (
<Admin
dataProvider={...}
theme={lightTheme}
darkTheme={darkTheme}
>
// ...
</Admin>
);
With this setup, the default application theme depends on the user’s system settings. If the user has chosen a dark mode in their OS, react-admin will use the dark theme. Otherwise, it will use the light theme.
In addition, users can switch from one theme to the other using the <ToggleThemeButton>
component, which appears in the AppBar as soon as you define a darkTheme
prop.
Changing the Theme Programmatically
React-admin provides the useTheme
hook to read and update the theme programmatically. It uses the same syntax as useState
. Its used internally by the <ToggleThemeButton>
component.
import { defaultTheme, useTheme } from 'react-admin';
import { Button } from '@mui/material';
const ThemeToggler = () => {
const [theme, setTheme] = useTheme();
return (
<Button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
{theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme'}
</Button>
);
}
Customizing The Sidebar Width
You can specify the Sidebar
width by setting the width
and closedWidth
properties on your custom Material UI theme:
import { defaultTheme } from 'react-admin';
const theme = {
...defaultTheme,
sidebar: {
width: 300, // The default value is 240
closedWidth: 70, // The default value is 55
},
};
const App = () => (
<Admin theme={theme} dataProvider={...}>
// ...
</Admin>
);
For more advanced sidebar theming, pass your own Sidebar
component to a custom Layout
:
import { Sidebar, Layout } from 'react-admin';
const MySidebar = (props) => (
<Sidebar
sx={{
"& .RaSidebar-drawerPaper": {
backgroundColor: "red",
},
}}
{...props}
/>
);
const MyLayout = props => <Layout {...props} sidebar={MySidebar} />
Writing a Custom Theme
Material UI theming also allows to change the default palette, typography, colors, etc. This is very useful to change the react-admin style to match the branding of your company.
A theme
object can contain the following keys:
breakpoints
direction
mixins
components
palette
props
shadows
spacing
transitions
typography
zIndex
Tip: Check Material UI default theme documentation to see the default values and meaning for these keys.
import { lime, purple } from '@mui/material/colors';
const theme = {
palette: {
primary: {
main: '#FF5733',
// light: will be calculated from palette.primary.main,
// dark: will be calculated from palette.primary.main,
// contrastText: will be calculated to contrast with palette.primary.main
},
secondary: {
main: '#E0C2FF',
light: '#F5EBFF',
// dark: will be calculated from palette.secondary.main,
contrastText: '#47008F',
},
},
spacing: 4,
typography: {
fontFamily: 'Raleway, Arial',
},
components: {
MuiCssBaseline: {
styleOverrides: `
@font-face {
font-family: 'Raleway';
font-style: normal;
font-display: swap;
font-weight: 400;
src: local('Raleway'), local('Raleway-Regular'), url(${RalewayWoff2}) format('woff2');
unicodeRange: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF;
}
`,
},
},
};
Once your theme is defined, pass it to the <Admin>
component, in the theme
prop.
const App = () => (
<Admin theme={myTheme} dataProvider={...}>
// ...
</Admin>
);
You can write a custom theme from scratch, or start from the default theme and override some values:
import { defaultTheme } from 'react-admin';
const theme = {
...defaultTheme,
components: {
...defaultTheme.components,
RaDatagrid: {
styleOverrides: {
root: {
backgroundColor: "Lavender",
"& .RaDatagrid-headerCell": {
backgroundColor: "MistyRose",
},
}
}
}
}
};
Default Theme
React-admin provides a theme that customizes a few Material-UI settings. You can import and use this react-admin default theme as a starting point for your custom theme:
import { defaultTheme } from 'react-admin';
const myTheme = {
...defaultTheme,
palette: {
...defaultTheme.palette,
secondary: {
main: '#11cb5f',
},
},
};
Here is the default theme:
import { RaThemeOptions } from './layout/Theme';
const defaultThemeInvariants = {
typography: {
h6: {
fontWeight: 400,
},
},
sidebar: {
width: 240,
closedWidth: 50,
},
components: {
MuiTextField: {
defaultProps: {
variant: 'filled' as const,
margin: 'dense' as const,
size: 'small' as const,
},
},
MuiFormControl: {
defaultProps: {
variant: 'filled' as const,
margin: 'dense' as const,
size: 'small' as const,
},
},
},
};
export const defaultLightTheme: RaThemeOptions = {
palette: {
background: {
default: '#fafafb',
},
secondary: {
light: '#6ec6ff',
main: '#2196f3',
dark: '#0069c0',
contrastText: '#fff',
},
},
...defaultThemeInvariants,
components: {
...defaultThemeInvariants.components,
MuiFilledInput: {
styleOverrides: {
root: {
backgroundColor: 'rgba(0, 0, 0, 0.04)',
'&$disabled': {
backgroundColor: 'rgba(0, 0, 0, 0.04)',
},
},
},
},
},
};
export const defaultDarkTheme: RaThemeOptions = {
palette: {
mode: 'dark',
primary: {
main: '#90caf9',
},
background: {
default: '#313131',
},
},
...defaultThemeInvariants,
};
export const defaultTheme = defaultLightTheme;