Spacing math with theme.spacing() in MUI v5

Viewed 2533

In MUI v4, I had bits like this in my JSS classes:

paddingTop: theme.mixins.toolbar.minHeight + theme.spacing(1)

In v5 however, theme.spacing() returns a string instead of a number. So the above statement would set paddingTop to 568px, which is 56+'8px' So what is now the proper way to do math with spacing?

3 Answers

MUI Theme is just an object, you can extend its functionalities from the base theme pretty easily. Once you define and inject your custom theme through ThemeProvider component, you can start using it anywhere in the children.

The method below create an enhanced version of the original theme with a new method gap(spacing) that returns the space value in number without the px unit at the end. You can also use theme.space[index] to access the value as another alternative:

const createExtendedTheme = () => {
  const defaultTheme = createTheme();
  const gap = (spacing: number) => parseInt(defaultTheme.spacing(spacing), 10);

  return createTheme({
    gap,
    space: {
      0: gap(0),
      1: gap(1),
      2: gap(2),
      3: gap(3),
      4: gap(4),
      5: gap(5),
    },
  });
};
// For Typescript users
declare module '@mui/material/styles' {
  interface ExtendedTheme {
    gap: (spacing: number) => number;
    space: {
      0: number;
      1: number;
      2: number;
      3: number;
      4: number;
      5: number;
    };
  }
  interface Theme extends ExtendedTheme {}
  interface ThemeOptions extends ExtendedTheme {}
}

Usage

const theme = createExtendedTheme();

export default function CustomStyles() {
  return (
    <ThemeProvider theme={theme}>
      <Content />
    </ThemeProvider>
  );
}
function Content() {
  const theme = useTheme();

  return (
    <Box
      sx={{
        width: theme.gap(5) * 2,
        height: theme.gap(1) + theme.gap(2),
        height: theme.space[1] + theme.space[2], // same as above
        bgcolor: "tomato"
      }}
    />
  );
}

Live Demo

Codesandbox Demo

`calc(${theme.mixins.toolbar.minHeight} + ${theme.spacing(1)})`

You can override the theme to provide another function that returns the spacing as a number:

// If you are using Typescript
declare module '@mui/material/styles' {
  interface ExtendedTheme {
    spacingNumber(spacing: number): number;
  }
  interface Theme extends ExtendedTheme {}
}

const createExtendedTheme = () => {
  const defaultTheme = createTheme();
  const spacingNumber = (spacing) => Number(theme.spacing(spacing).slice(0, -2));

  return createTheme({
    spacingNumber
  });
};

Usage

const theme = createExtendedTheme();

export default function CustomStyles() {
  return (
    <ThemeProvider theme={theme}>
      <Content />
    </ThemeProvider>
  );
}

See: https://github.com/mui/material-ui/issues/29086

Related