Skip to content

Themed components

Learn how to apply custom styles to components at the theme level.

Component identifier

If you've used Material UI, you are probably familiar with this technique. To theme a specific component, specify the component identifier (Joy{ComponentImportName}) inside the components node.

  • Use defaultProps to change the default props of the component.
  • Use styleOverrides to apply styles to each component slots. All Joy UI component contains the root slot.

Check the components.d.ts file to see every component identifier.

import { CssVarsProvider, extendTheme } from '@mui/joy/styles';

const theme = extendTheme({
  components: {
    JoyChip: {
      defaultProps: {
        size: 'sm',
      },
      styleOverrides: {
        root: {
          borderRadius: '4px',
        },
      },
    },
  },
});

function App() {
  return <CssVarsProvider theme={theme}>...</CssVarsProvider>;
}

Using design tokens per props

To change the styles of a given prop using design tokens values from the theme, use a callback as value to the style overrides. The argument contains theme and ownerState (props).

extendTheme({
  components: {
    JoyChip: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          ...(ownerState.size === 'sm' && {
            borderRadius: theme.vars.radius.xs,
          }),
          ...(ownerState.size === 'md' && {
            borderRadius: theme.vars.radius.sm,
            background: `linear(to top, ${
              theme.vars.palette[ownerState.color][700]
            }, ${theme.vars.palette[ownerState.color][500]})`,
          }),
        }),
      },
    },
  },
});

We recommend to use CSS variables from theme.vars.* because it has a better debugging experience and also is more performant in some cases.

However, the new styles can also contain any CSS selectors (support nested selectors), as such:

extendTheme({
  components: {
    JoyChip: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          ...(ownerState.variant === 'solid' &&
            ownerState.clickable && {
              color: 'rgba(255 255 255 / 0.72)',
              '&:hover': {
                color: '#fff',
              },
              '&.Mui-disabled': {
                opacity: 0.6,
              },
            }),
        }),
      },
    },
  },
});

Different styles per mode

To specify different values than the ones defined in the default theme for each mode (light and dark), use the CSS attribute selector.

Joy UI attaches a data-* attribute with the current color scheme to the DOM (HTML by default). You can use the theme.getColorSchemeSelector utility to change the component styles.

The example below illustrate how you'd change the intensity of the boxShadow token in the light mode while removing it completely in the dark mode:

extendTheme({
  components: {
    JoyChip: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          // for the default color scheme (light)
          boxShadow: theme.vars.shadow.sm,

          // the result is `[data-joy-color-scheme="dark"] &`
          [theme.getColorSchemeSelector('dark')]: {
            boxShadow: 'none',
          },
        }),
      },
    },
  },
});

If you have custom color schemes defined, this approach also works. However, note that it creates additional CSS specificity which might be cumbersome when the parent component wants to override their children styles.