Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[theme] Custom Variant #15573

Closed
2 tasks done
philip-lf opened this issue May 3, 2019 · 32 comments
Closed
2 tasks done

[theme] Custom Variant #15573

philip-lf opened this issue May 3, 2019 · 32 comments
Labels
new feature New feature or request priority: important This change can make a difference
Milestone

Comments

@philip-lf
Copy link

philip-lf commented May 3, 2019

  • This is not a v0.x issue.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 🤔

I would love the ability to use a variant with any string and with that variant I could style the component using theme overrides. For example, let's say I have 4 types of buttons throughout my app and each button has a custom variant, inside theme I would simply use MuiButton with my custom variant names and style them as I please. The variant would act as an identifier and would give the theme more flexibility in styling the entire app and it would not tie me down to a preset list of variants.

Current Behavior 😯

Currently variants are limited and come with additional styling.

Context 🔦

Limits my ability to use theme to a greater extent and pushes me to style more locally than globally.

@eps1lon
Copy link
Member

eps1lon commented May 3, 2019

I'm not sure what you're asking for. It sounds like you can already do this via

import MuiButton from '@material-ui/core/Button';

function Button({ variant, ...muiButtonProps }) {
  if (variant === 'fancy') {
    return <MyButtonForVariantFancy />
  }
  return <MuiButton {...muiButtonProps} />
}

<Button variant="raised">Raised Material-UI</Button>
<Button variant="fancy">Fancy</Button/>

@eps1lon eps1lon added the new feature New feature or request label May 3, 2019
@oliviertassinari
Copy link
Member

@philip-lf Could it be a duplicate of #13875 or #15454?

@philip-lf
Copy link
Author

Thanks for your responses. @oliviertassinari , I don't believe they are the same.
Currently for Button I have these variants accessible to me:
Screen Shot 2019-05-03 at 8 51 43 AM

Given two buttons, one with an outlined variant and the other without, the theme can target the button with the variant and style it specifically like this:

<Button  variant="outlined">
     Outlined Button
</Button>

<Button>
     Button
</Button>
const theme = createMuiTheme({
     overrides: {
          MuiButton: {
               root: {
                    backgroundColor: 'red'
               },
               outlined: {
                    backgroundColor: 'blue'
               }
          }
     }
})

The feature I would hope for is that a variant of any name can be applied and targeted through the theme. It would look something like this:

<Button  variant="customVariantName">
     Custom Button
</Button>

const theme = createMuiTheme({
     overrides: {
          MuiButton: {
               root: {
                    backgroundColor: 'red'
               },
               customVariantName: {
                    backgroundColor: 'blue'
               }
          }
     }
})

The variant would act as an identifier that could be accessed through the theme. So instead of applying unique styles to every component I would centralize my styles in one place.

@oliviertassinari
Copy link
Member

@philip-lf Thank you for detailing the use case! It's definitely a problem we are interested in solving. It looks like a duplicate. In theory, if we solve the problem for the color prop, we can solve it too for the variant prop with little effort.

@oliviertassinari oliviertassinari added this to the v5 milestone May 3, 2019
@romanr
Copy link
Contributor

romanr commented Jul 4, 2019

I am interested in creating custom variant in Typography. It seems to be working, however there are errors in console.

Theme:

const theme = createMuiTheme({
 MuiTypography: {
   question: {
        fontSize: '14px',
        fontWeight: 'bold',
      }
 }
}

Code:

<Typography variant="question" > text </Typography>

Just works!

But with error in console: 🤕

checkPropTypes.js:19 Warning: Failed prop type: Invalid prop `variant` of value `question` supplied to `ForwardRef(Typography)`, expected one of ["h1","h2","h3","h4","h5","h6","subtitle1","subtitle2","body1","body2","caption","button","overline","srOnly","inherit"].
    in ForwardRef(Typography) (created by WithStyles(ForwardRef(Typography)))
    in WithStyles(ForwardRef(Typography)) (created by FormLayoutDemo)
    in div (created by ForwardRef(Grid))

So the only change required is to not to threat this as an error?

@oliviertassinari
Copy link
Member

oliviertassinari commented Jul 4, 2019

@romanr Thanks for experimenting around with it. People using TypeScript will also have an issue with the accepted values. I think that we can soften the static prop types to accept more values. The challenge is to keep the default values documented, while ideally have a dynamic check to make sure the variant you are trying to use is defined.

@HashemKhalifa
Copy link

any update regarding the variant error in console? Warning: Failed prop type: Invalid prop variant`?

@neolefty
Copy link

Typescript — yes it would be lovely to able to use this without compiler errors.

@DHedgecock
Copy link

This would be extremely helpful for creating Typography variants, our team wants to create more semantically named variants like sectionTitle, mutedHint, graphLegend etc. that we manage in the theme definition.

@oliviertassinari oliviertassinari removed the priority: important This change can make a difference label Dec 1, 2019
@rob2d
Copy link

rob2d commented Dec 5, 2019

To add to that -- it's also just a bit nicer not to need to rely on variants involving older HTML element entities such as hx when you run out of sizes -- they are not entirely intuitive for things other than Headers (as the prefix involves). I currently have to resort to this as we designed around body1, body2 and caption which does not encompass enough variation for the main content in our designs -- then you end up with a choice of that vs overriding font sizes -- entirely defeating the purpose of Typography (!) 😢

@kylealwyn
Copy link

MaterialUI has been a pleasure to work with but I'm surprised about the lack of support for custom colors/variants. I see this is bookmarked for v5 but the Oct. 2020 due date is some time away. Are there any updates / plans to support this in v4?

@oliviertassinari oliviertassinari self-assigned this Feb 2, 2020
@oliviertassinari oliviertassinari added the priority: important This change can make a difference label Feb 2, 2020
@jeromeSH26

This comment has been minimized.

@RehabHussein
Copy link

Hi @oliviertassinari when do you think we can have this feature ? I really appreciate your hard work !

@zeckdude
Copy link
Contributor

I'd love to see this sooner as well. Any chance to release this in some sort of beta?

@mahesh-kedari
Copy link

This will surely help to extend components with lot of flexibility.

@anisg
Copy link

anisg commented Mar 11, 2020

With this feature and style System expands to all components (and not just Box), this will be for me the best UI Toolkit ever.

@mehuljariwala
Copy link

<Typography variant="question" > text </Typography>

@roma @oliviertassinari
In My case, this is not working can you please check this.

https://codesandbox.io/s/material-demo-cw4in?file=/demo.tsx

@majelbstoat
Copy link

@mehuljariwala you shouldn't expect this to work yet, I don't think. That's what this issue is open to ask for, and the most recent PR to attempt to fix it - #20203 - was closed without being merged.

@ghost
Copy link

ghost commented May 28, 2020

Any updates about this "feature"? (this looks so simple to achieve if you think about the other possibilities that the theme provides, yet... I know about the static thing...)

@WongyuChoi
Copy link

WongyuChoi commented May 29, 2020

My approach can be unsafe, but the code below works at least to add custom Variant type. If you see a hidden danger in this approach, please let me know--I just started using TS...

declare module '@material-ui/core/styles/createTypography' {
  export interface Theme {
    noDecoLink?: NoDecoLink;
  }
  export interface ThemeOptions {
    noDecoLink?: NoDecoLink;
  }
  export type CustomVariant =
    | 'h1' // From to this point, defined in the vanilla Variant
    | 'h2' // let me know if I do not need this vanilla portion...
    | 'h3'
    | 'h4'
    | 'h5'
    | 'h6'
    | 'subtitle1'
    | 'subtitle2'
    | 'body1'
    | 'body2'
    | 'caption'
    | 'button'
    | 'overline' // up to this point, defined as vanilla Variant
    | 'root' // newly added variant
    | 'tab'; // end of newly added variant

  // below is simple copy and paste from the createTypography.d.ts
  export interface Typography
    extends Record<CustomVariant, TypographyStyle>,
      FontStyle,
      TypographyUtils {}

  export interface TypographyOptions
    extends Partial<
      Record<CustomVariant, TypographyStyleOptions> & FontStyleOptions
    > {}
}

@EWOTE
Copy link

EWOTE commented May 29, 2020

@WongyuChoi
Unfortunately, this unsafe and won't work because this allows you to add custom variants but when you try to use this variant, you will get a type error after all. You still need to redefine TypographyTypeMap at the moment, but this is not possible, as far as I understand.

@ValentinH
Copy link
Contributor

@romanr Thanks for experimenting around with it. People using TypeScript will also have an issue with the accepted values. I think that we can soften the static prop types to accept more values. The challenge is to keep the default values documented, while ideally have a dynamic check to make sure the variant you are trying to use is defined.

Having strict prop types by default is one of the awesome features of MUI. It enables auto completion in the editor and provides a really nice development experience.

@doublejosh
Copy link

Would be great if custom button variants worked like typography...

function makeTypography (baseTheme: Theme): MyTypography {
  return {
    ...baseTheme.typography,
    myRedText: {
      color: red,
    }
  }
}

function makeMyTheme(theme: Theme) {
  return {
    ...theme,
    typography: makeTypography(theme),
  }
}

@manuelbenitez

This comment has been minimized.

@kcarra
Copy link

kcarra commented Nov 9, 2020

At least in v5 I've been able to get around this issue by using variants in my components theme:

import { createMuiTheme } from '@material-ui/core/styles';

const theme = createMuiTheme({
  components: {
    MuiButton: {
      variants: [
        {
          props: { variant: 'twitter' },
          style: {
            backgroundColor: '#00acee',
            color: '#FFFFFF',
            "&:hover": {
              backgroundColor: "#007cad",
            },
          },
        },
        {
          props: { variant: 'facebook' },
          style: {
            backgroundColor: '#3b5998',
            color: '#FFFFFF',
            "&:hover": {
              backgroundColor: "#314c85",
            },
          },
        },
      ],
    },
  },
});

export default theme

Then use the button like so:

<Grid item>
    <Button variant="facebook" startIcon={<FacebookIcon />}>Facebook</Button>
</Grid>
<Grid item>
    <Button variant="twitter" startIcon={<TwitterIcon />}>Twitter</Button>
</Grid>

I was hoping to be able to do this with the color prop as well in v5, but have not been able to get it to work. 13875 was the closest issue I found to being able to customize the color prop. I would ideally like to be able to do:

const theme = createMuiTheme({
  palette: {
    twitter: {
      main: '#00acee'
    },
    facebook: {
      main: '#3b5998'
    }
  }
})

in my theme then:

<Grid item>
    <Button color="facebook" startIcon={<FacebookIcon />}>Facebook</Button>
</Grid>
<Grid item>
    <Button color="twitter" startIcon={<TwitterIcon />}>Twitter</Button>
</Grid>

As of v5 I havent been able to get something that prevents the prop error saying color "facebook" isnt ["primary", "secondary", "Etc...]

@oliviertassinari
Copy link
Member

@kcarra Thanks for trying it out! We plan to continue pushing in this direction for v5:

  • This issue is still open to explore how we can extend the support of theme.components.X.variants to any prop, as you did with the <Button variant="">.
  • For a direct mapping between the color and the theme's palette, bypassing theme.components.X.variants, [theme] Allow custom color variants #13875 is the issue to follow.

@kcarra
Copy link

kcarra commented Nov 10, 2020

@oliviertassinari I'm wondering if this issue can be closed then. As far as creating custom variants this seems to be working as expected in V5 using variants in your theme

@julianoappelklein
Copy link

julianoappelklein commented Jan 13, 2021

If someone wants to avoid typescript errors in V4:

<Button variant={'twitter' as any} ... >...</Button>

@Ravindersingh1526
Copy link

Ravindersingh1526 commented Apr 5, 2021

I want to add custom variant in version 4. I have created my application with typescript.

For the following example variant is successfully added and working fine but i receive the typescript prediction errors

const FancyButton = withStyles ({
root: {........},
contained: {..............},
containedPrimary: {........................},
customVariant: {
backgroundColor: "red",
}
})(Button);

<FancyButton variant="customVariant">Click</FancyButton>
// example is working fine but typescript prediction errors show on compile time.

How i solve typescript prediction

@mnajdova
Copy link
Member

mnajdova commented Apr 5, 2021

How i solve typescript prediction

@Ravindersingh1526 you need to add these new variants with TypeScript module augmentation, please see https://next.material-ui.com/customization/theme-components/#adding-new-component-variants for an example.

@mnajdova
Copy link
Member

mnajdova commented Apr 5, 2021

As this API is already available, I am closing this issue. You can take a look on how it can be done on this guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request priority: important This change can make a difference
Projects
None yet
Development

No branches or pull requests