Skip to content

Latest commit

 

History

History
592 lines (484 loc) · 17.6 KB

AppTheme.md

File metadata and controls

592 lines (484 loc) · 17.6 KB
layout title
default
Application Theme

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.

The e-commerce demo contains a theme switcher, so you can test them in a real application.

Setting The Application Theme

You can override the style of the entire application by passing a custom theme to the <Admin> component:

import { Admin, defaultTheme } from 'react-admin';
import { deepmerge } from '@mui/utils';
import indigo from '@mui/material/colors/indigo';
import pink from '@mui/material/colors/pink';
import red from '@mui/material/colors/red';

const myTheme = deepmerge(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={myTheme}>
        // ...
    </Admin>
);

You can either use built-in themes, or write your own.

Note that you don't need to call Material-UI's createTheme yourself. React-admin will do it for you.

Light And Dark Themes

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 provides a built-in dark theme by default, 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, that appears in the AppBar as soon as you define a darkTheme prop.

You can override the dark theme by setting the <Admin>'s darkTheme prop with your own theme:

import { Admin, defaultDarkTheme, defaultLightTheme } from 'react-admin';
import { deepmerge } from '@mui/utils';

const lightTheme = defaultLightTheme;
const darkTheme = deepmerge(defaultDarkTheme, { palette: { mode: 'dark' } });

const App = () => (
    <Admin
        dataProvider={...}
        theme={lightTheme}
        darkTheme={darkTheme}
    >
        // ...
    </Admin>
);

Tip: If you don't need the default dark theme, you can set the <Admin>'s darkTheme prop to null:

const App = () => (
    <Admin darkTheme={null}>
        // ...
    </Admin>
);

Tip: If you provide both a theme and a darkTheme, react-admin will choose the default theme to use for each user based on their OS preference. If you prefer to always default to the light or the dark theme regardless of the user’s OS preference, you can set the <Admin defaultTheme> prop to either "light" or "dark":

const App = () => (
    <Admin defaultTheme="light">
        // ...
    </Admin>
);

Built-In Themes

React-admin comes with 4 built-in themes, each one having a light and a dark variant. You can use them as a starting point for your custom theme, or use them as-is.

Default

The default theme is a good fit for every application, and works equally well on desktop and mobile.

Default light theme Default light theme Default dark theme Default dark theme

You don't need to configure anything to use the default theme - it comes out of the box with react-admin.

Nano

A dense theme with minimal chrome, ideal for complex apps. It uses a small font size, reduced spacing, text buttons, standard variant inputs, pale colors. Only fit for desktop apps.

Nano light theme Nano light theme Nano dark theme Nano dark theme

To use the Nano theme, import the nanoLightTheme and nanoDarkTheme objects, and pass them to the <Admin> component:

import { Admin, nanoLightTheme, nanoDarkTheme } from 'react-admin';
import { dataProvider } from './dataProvider';

export const App = () => (
    <Admin
        dataProvider={dataProvider}
        theme={nanoLightTheme}
        darkTheme={nanoDarkTheme}
    >
        // ...
    </Admin>
);

You must also import the Onest font in your index.html file:

<link href="https://fonts.googleapis.com/css2?family=Onest:wght@300;400;500;700&display=swap" rel="stylesheet">

Radiant

A theme emphasizing clarity and ease of use. It uses generous margins, outlined inputs and buttons, no uppercase, and an acid color palette.

Radiant light theme Radiant light theme Radiant dark theme Radiant dark theme

To use the Radiant theme, import the radiantLightTheme and radiantDarkTheme objects, and pass them to the <Admin> component:

import { Admin, radiantLightTheme, radiantDarkTheme } from 'react-admin';
import { dataProvider } from './dataProvider';

export const App = () => (
    <Admin
        dataProvider={dataProvider}
        theme={radiantLightTheme}
        darkTheme={radiantDarkTheme}
    >
        // ...
    </Admin>
);

You must also import the Gabarito font in your index.html file:

<link href="https://fonts.googleapis.com/css2?family=Gabarito:wght@500;600;700;900&display=swap" rel="stylesheet">

House

A young and joyful theme. It uses rounded corners, blurry backdrop, large padding, and a bright color palette.

House light theme House light theme House dark theme House dark theme

To use the House theme, import the houseLightTheme and houseDarkTheme objects, and pass them to the <Admin> component:

import { Admin, houseLightTheme, houseDarkTheme } from 'react-admin';
import { dataProvider } from './dataProvider';

export const App = () => (
    <Admin
        dataProvider={dataProvider}
        theme={houseLightTheme}
        darkTheme={houseDarkTheme}
    >
        // ...
    </Admin>
);

You must also import the Open Sans font in your index.html file:

<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;500;600;700&display=swap" rel="stylesheet">

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>
    );
}

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';
import { deepmerge } from '@mui/utils';

const theme = deepmerge(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 the sx 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';
import { deepmerge } from '@mui/utils';

const theme = deepmerge(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';
import { deepmerge } from '@mui/utils';

const theme = deepmerge(defaultTheme, {
    components: {
        MuiTextField: {
            defaultProps: {
                variant: 'outlined' as const,
            },
        },
        MuiFormControl: {
            defaultProps: {
                variant: 'outlined' as const,
            },
        },
    }
});

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';
import { deepmerge } from '@mui/utils';

const theme = deepmerge(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:

{% raw %}

import { Sidebar, Layout } from 'react-admin';

const MySidebar = (props) => (
    <Sidebar
        sx={{
            "& .RaSidebar-drawerPaper": {
                backgroundColor: "red",
            },
        }}
        {...props}
    />
);

const MyLayout = ({ children }) => (
    <Layout sidebar={MySidebar}>
        {children}
    </Layout>
);

{% endraw %}

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, using Material UI's utility function deepmerge:

import { deepmerge } from '@mui/utils';
import { defaultTheme } from 'react-admin';

const theme = deepmerge(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';
import { deepmerge } from '@mui/utils';

const myTheme = deepmerge(defaultTheme, {
    palette: {
        secondary: {
            main: '#11cb5f',
        },
    },
});

Here is the default theme:

import { RaThemeOptions } from './types';
import { deepmerge } from '@mui/utils';

const defaultThemeInvariants = {
    typography: {
        h6: {
            fontWeight: 400,
        },
    },
    sidebar: {
        width: 240,
        closedWidth: 50,
    },
    components: {
        MuiAutocomplete: {
            defaultProps: {
                fullWidth: true,
            },
            variants: [
                {
                    props: {},
                    style: ({ theme }) => ({
                        [theme.breakpoints.down('sm')]: { width: '100%' },
                    }),
                },
            ],
        },
        MuiTextField: {
            defaultProps: {
                variant: 'filled' as const,
                margin: 'dense' as const,
                size: 'small' as const,
                fullWidth: true,
            },
            variants: [
                {
                    props: {},
                    style: ({ theme }) => ({
                        [theme.breakpoints.down('sm')]: { width: '100%' },
                    }),
                },
            ],
        },
        MuiFormControl: {
            defaultProps: {
                variant: 'filled' as const,
                margin: 'dense' as const,
                size: 'small' as const,
                fullWidth: true,
            },
        },
        RaSimpleFormIterator: {
            defaultProps: {
                fullWidth: true,
            },
        },
        RaTranslatableInputs: {
            defaultProps: {
                fullWidth: true
            },
        },
    },
};

export const defaultLightTheme: RaThemeOptions = deepmerge(
    defaultThemeInvariants,
    {
        palette: {
            background: {
                default: '#fafafb',
            },
            secondary: {
                light: '#6ec6ff',
                main: '#2196f3',
                dark: '#0069c0',
                contrastText: '#fff',
            },
        },
        components: {
            MuiFilledInput: {
                styleOverrides: {
                    root: {
                        backgroundColor: 'rgba(0, 0, 0, 0.04)',
                        '&$disabled': {
                            backgroundColor: 'rgba(0, 0, 0, 0.04)',
                        },
                    },
                },
            },
        },
    }
);

export const defaultDarkTheme: RaThemeOptions = deepmerge(
    defaultThemeInvariants,
    {
        palette: {
            mode: 'dark',
            primary: {
                main: '#90caf9',
            },
            background: {
                default: '#313131',
            },
        },
    }
);

export const defaultTheme = defaultLightTheme;