Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating custom variants with Material UI

I am trying to create custom variants for the Button component in Material UI.

My first step is to create a component-based off of the Button component with the styles that I want:

// CTA.js

import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";

const useStyles = makeStyles({
  root: { // CUSTOM__STYLES },
  label: { // CUSTOM__STYLES },
});

const CTA = ({ children }) => {
  const classes = useStyles();

  return (
    <Button
      classes={{
        root: classes.root, 
        label: classes.label,
      }}
    >
      {children}
    </Button>
  );
};

I then import that component into a new Button component that I am creating as follows:

// Button.js
import MuiButton from "@material-ui/core/Button";
import CTA from "./CTA";

const Button = ({ variant, ...muiButtonProps }) => {
  if (variant === "cta") {
    return <CTA {...muiButtonProps} />;
  }
  return <MuiButton {...muiButtonProps} />;
};

Now, what I want is to be able to import my new Button component and have it work just like a regular Material-UI button component, but with the addition of variant="cta". However, it does not quite work.

For example, take a look at the following:

// Header.js
import { Button as MuiButton } from "@material-ui/core";
import { Button } from "@/theme/button.js";

...

<MuiButton variant="outlined">Mui Button</MuiButton>  // works
<Button variant="outlined">Button</Button> // does not work
<Button variant="cta">CTA Button</Button>  // works

I see that my new custom Button component works when I use variant="cta", but it does not work when I use any of the built-in Material-UI variant options. I cannot figure out what that is. I would have thought that <Button variant="outlined"> would work just like <MuiButton variant="outlined">. But that is not the case.

Any idea why not and how to fix it?

like image 570
Moshe Avatar asked Sep 14 '25 08:09

Moshe


2 Answers

In Material-UI v5, you can easily create a new variants for your components (See the list of supported components in this RFC) using createTheme() which removes the need to create wrapper components. Below is the minimum example:

const theme = createTheme({
  components: {
    MuiButton: {
      variants: [
        {
          props: { variant: 'dashed' },
          style: {
            textTransform: 'none',
            border: `2px dashed grey${blue[500]}`,
          },
        },
      ],
    },
  },
});
export default function Demo() {
  return (
    <ThemeProvider theme={theme}>
      <Button variant="outlined">
        Outline
      </Button>
      <Button variant="dashed">
        Dashed
      </Button>
    </ThemeProvider>
  );
}

For typescript users, you also need to update the variant definition using module augmentation.

declare module '@mui/material/Button' {
  interface ButtonPropsVariantOverrides {
    dashed: true;
  }
}

Live Demo

Edit GlobalThemeVariants Material Demo

like image 157
NearHuscarl Avatar answered Sep 15 '25 20:09

NearHuscarl


Two options are possible, it dont work cause you destruct "variant" and don't forward it to your MuiButton.

You can do it this way in your Button.js

const Button = ({ variant, ...muiButtonProps }) => {
  if (variant === "cta") {
    return <CTA {...muiButtonProps} />;
  }
  return <MuiButton variant={variant} {...muiButtonProps} />;
};

or

const Button = (muiButtonProps) => {
  if (muiButtonProps.variant === "cta") {
    return <CTA {...muiButtonProps} />;
  }
  return <MuiButton {...muiButtonProps} />;
};

Take a look at the docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

// Stage 4(finished) proposal
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}
like image 45
Jakob Lämmle Avatar answered Sep 15 '25 21:09

Jakob Lämmle