Skip to content
Skip to content

Approaches

Learn which approach is recommended, depending on the situation, to customize Joy UI components.

  • For customizing only a specific instance of a given component, use the sx prop.
  • To ensure every instance of a given component looks the same across you app, use theming.
  • To create something that Joy UI doesn't support out of the box but still has design consistency, create a reusable component that uses Joy UI's theme design tokens.

sx prop

The sx prop provides a superset of CSS (contains all CSS properties/selectors, in addition to custom ones) that maps values directly from the theme, depending on the CSS property used.

Every Joy UI component supports it and it's a tool that allows you to quickly customize components on the spot. Visit the sx prop documentation to learn more about it.

Theming

The theme is an object where you define both your design language with foundational tokens such as color schemes, typography and spacing scales, and how each component, and their different variants and states, uses them.

Here are some examples that reproduce popular designs (only the light mode, though):

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

const githubTheme = extendTheme({
  colorSchemes: {
    light: {
      palette: {
        success: {
          solidBg: '#2DA44E',
          solidHoverBg: '#2C974B',
          solidActiveBg: '#298E46',
        },
        neutral: {
          outlinedBg: '#F6F8FA',
          outlinedHoverBg: '#F3F4F6',
          outlinedActiveBg: 'rgba(238, 239, 242, 1)',
          outlinedBorder: 'rgba(27, 31, 36, 0.15)',
        },
        focusVisible: 'rgba(3, 102, 214, 0.3)',
      },
    },
  },
  focus: {
    default: {
      outlineWidth: '3px',
    },
  },
  fontFamily: {
    body: 'SF Pro Text, var(--gh-fontFamily-fallback)',
  },
  components: {
    JoyButton: {
      styleOverrides: {
        root: ({ ownerState }) => ({
          borderRadius: '6px',
          boxShadow: '0 1px 0 0 rgba(27, 31, 35, 0.04)',
          transition: '80ms cubic-bezier(0.33, 1, 0.68, 1)',
          transitionProperty: 'color,background-color,box-shadow,border-color',
          ...(ownerState.size === 'md' && {
            fontWeight: 600,
            minHeight: '32px',
            fontSize: '14px',
            '--Button-paddingInline': '1rem',
          }),
          ...(ownerState.color === 'success' &&
            ownerState.variant === 'solid' && {
              '--gh-palette-focusVisible': 'rgba(46, 164, 79, 0.4)',
              border: '1px solid rgba(27, 31, 36, 0.15)',
              '&:active': {
                boxShadow: 'inset 0px 1px 0px rgba(20, 70, 32, 0.2)',
              },
            }),
          ...(ownerState.color === 'neutral' &&
            ownerState.variant === 'outlined' && {
              '&:active': {
                boxShadow: 'none',
              },
            }),
        }),
      },
    },
  },
});

function App() {
  return (
    <CssVarsProvider theme={githubTheme}>
      <Button>Solid</Button>
      ...other buttons
    </CssVarsProvider>
  );
};

Customizing theme tokens

Theme tokens refer to both low-level and global variant design tokens.

For example, instead of assigning the same hex code every time you want to change a given component's background color, you assign a theme token instead. If, at any point, you want to change that, you'd change in one place only, ensuring you consistency across all the components that use that theme token.

To print your own design language into Joy UI components, start by customizing these tokens first, as every component uses them.

To do that, always use the extendTheme function as the customized tokens will be deeply merged into the default theme. Under the hood, Joy UI will convert the tokens to CSS variables, enabling you to get them through theme.vars.*, which is very convenient as you can use any styling solution to read those CSS vars.

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

const theme = extendTheme({
  colorSchemes: {
    light: {
      palette: {
        // affects all Joy components that has `color="primary"` prop.
        primary: {
          50: '#fffbeb',
          100: '#fef3c7',
          200: '#fde68a',
          // 300, 400, ..., 800,
          900: '#78350f',
        },
      },
    },
  },
  fontFamily: {
    display: 'Inter, var(--joy-fontFamily-fallback)',
    body: 'Inter, var(--joy-fontFamily-fallback)',
  },
});

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

Customizing components

Each Joy UI component uses a pre-defined set of theme tokens. For example, the default small Button comes with fontSize: sm by default. To change that while ensuring that every instance of it has the same styles, do it targeting the component directly from the theme.

Here's a preview of how you'd change the button's font size to large:

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

const theme = extendTheme({
  components: {
    // The component identifier always start with `Joy${ComponentName}`.
    JoyButton: {
      styleOverrides: {
        root: ({ theme }) => {
          // theme.vars.* return the CSS variables.
          fontSize: theme.vars.fontSize.lg, // 'var(--joy-fontSize-lg)'
        },
      },
    },
  },
});

function MyApp() {
  return (
    <CssVarsProvider theme={theme}>
      <Button>Text</Button>
    </CssVarsProvider>
  );
}

Reusable component

Creating new and custom components is always an option when you don't find exactly what you're looking for. You can, however, ensure design consistency with other Joy UI components by pulling styles from the theme through the styled function.

You also gain the ability to use the sx prop, which also accepts theme tokens, to customize this newly created component.