Material-ui: How to use Material-UI theme with styled-components?

Created on 30 Jan 2018  路  19Comments  路  Source: mui-org/material-ui

How can I access the mui theme with the example shown in the documentation on how to use the styled components API?

question support

Most helpful comment

The recommended approach is to use two theme provider:

```jsx
import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import {
StylesProvider,
ThemeProvider as MuiThemeProvider,
createMuiTheme,
darken,
fade,
} from '@material-ui/core';

const myTheme = createMuiTheme();

const StyledButton = styled.button ${({ theme }) =>
padding: ${theme.spacing(1, 2)};
border: 1px solid;
cursor: pointer;
outline: 0;
border-radius: ${theme.shape.borderRadius}px;
color: ${theme.palette.primary.contrastText};
background-color: ${theme.palette.primary.main};
border-color: ${theme.palette.primary.main};
transition: ${theme.transitions.create(['background-color', 'box-shadow'])};
&:hover {
background-color: ${darken(theme.palette.primary.main, 0.1)};
border-color: ${darken(theme.palette.primary.main, 0.2)};
}
font-size: 18px;
${theme.breakpoints.up('md')} {
font-size: 16px;
}
} ;

export default function App() {
return (

Styled Components



);
}

All 19 comments

馃憢 Thanks for using Material-UI!

We use the issue tracker exclusively for bug reports and feature requests, however,
this issue appears to be a support request or question. Please ask on StackOverflow where the
community will do their best to help. There is a "material-ui" tag that you can use to tag your
question.

If you would like to link from here to your question on SO, it will help others find it.
If your issues is confirmed as a bug, you are welcome to reopen the issue using the issue template.

To clarify here, what I was wondering about was not with styled-components itself but in the documentation for beta.31 there is a section here
https://material-ui-next.com/customization/css-in-js/#styled-components-api-13-lines-
with an example. If its possible to access the mui theme value props in here it would be good to include that in the example. Would be interested to see how its done when using this method

Yes, if you get the theme from context yourself; otherwise you'd have to make it a component, and wrap it with the withTheme HOC, by which point you might as well just use JSS!

Please jump on gitter if you'd like to discuss further.

@mbrookes How do you get the theme from the context?

@einarpersson does this doc help?

Forgive me if I'm answering the wrong question, I think the question is " how can I am grab the mui theme in styled components to use in my styled components". I tried to simplify my solution down a bit, so there could be some typos.

// App/WithTheme.js

import React from 'react';
import {
  MuiThemeProvider,
  createMuiTheme,
  withTheme as muiWithTheme,
} from '@material-ui/core/styles';
import { ThemeProvider } from 'styled-components';
import PropTypes from 'prop-types';

const muiTheme = createMuiTheme({
  typography: {
    useNextVariants: true,
  },
});

function MaterialUiTheme(props) {
  return <MuiThemeProvider theme={muiTheme}>{props.children}</MuiThemeProvider>;
}

MaterialUiTheme.propTypes = {
  children: PropTypes.any,
};

const appTheme = { mode: 'light' };

function StyledComponentsTheme(props) {
  return (
    <ThemeProvider theme={{ app: appTheme, mui: props.theme }}>
      {props.children}
    </ThemeProvider>
  );
}

StyledComponentsTheme.propTypes = {
  children: PropTypes.any,
  theme: PropTypes.object,
};

const StyledComponentsThemeWithMui = muiWithTheme()(StyledComponentsTheme);

function WithTheme(props) {
  return (
    <MaterialUiTheme>
      <StyledComponentsThemeWithMui>
        {props.children}
      </StyledComponentsThemeWithMui>
    </MaterialUiTheme>
  );
}

WithTheme.propTypes = {
  children: PropTypes.any,
};

export default WithTheme;
// App/index.js

import WithTheme from './WithTheme';
import AppStuff from './AppStuff';

export default function App() {
  return (
    <AppWrapper>
      <WithTheme>
        <AppStuff />
      </WithTheme>
    </AppWrapper>
  );
}
// App/AppStuff.js
import styled from 'styled-components';
// import whatever else

// define AppStuff

export default const AppStuffStyled = styled(AppStuff)`
  margin-top: ${props => {
    console.log('styledProps', props); // manual check to see that we have theme w/ mui and app
    return props.theme.mui.spacing.unit;
  }};
`;

@bsherrill480 You could wrap your component in withTheme and style the enhanced one. This way you have access to the theme in the props.

If you want to access the theme when using the MUI styled component API, I think this shows an example of it: https://material-ui.com/customization/css-in-js/#styled-components-api-15-lines

There's a custom styled function:

// A function you can extract and put into its own module.
// Yes, 15 lines of code, it's all you need.
function styled(Component) {
  return (style, options) => {
    ...
    ...
  };
}

And you can use the theme like so:

const MyButton = styled(Button)(theme => ({
  backgroundColor: theme.palette.background.paper,
}));

@bsherrill480 answer is the one I was looking for. Here's his code in a bit less verbose way:

import React from "react";
import {
  createMuiTheme,
  MuiThemeProvider,
  withTheme as muiWithTheme,
} from "@material-ui/core/styles";
import { ThemeProvider } from "styled-components";
import PropTypes from "prop-types";

const muiTheme = createMuiTheme({
  typography: {
    useNextVariants: true,
  },
});

const MaterialUiTheme = props => (
  <MuiThemeProvider theme={muiTheme}>{props.children}</MuiThemeProvider>
);

const appTheme = {};

const StyledComponentsTheme = props => (
  <ThemeProvider theme={{ app: appTheme, mui: props.theme }}>
    {props.children}
  </ThemeProvider>
);

const StyledComponentsThemeWithMui = muiWithTheme()(StyledComponentsTheme);

const WithThemes = props => (
  <MaterialUiTheme>
    <StyledComponentsThemeWithMui>
      {props.children}
    </StyledComponentsThemeWithMui>
  </MaterialUiTheme>
);

WithThemes.propTypes = {
  children: PropTypes.any,
};

export default WithThemes;

I create this in my project so I can use 1 theme for both.

import React from 'react'
import PropTypes from 'prop-types'
import {ThemeProvider as StyledThemeProvider} from 'styled-components'
import {MuiThemeProvider} from '@material-ui/core/styles'
import {StylesProvider} from '@material-ui/styles'
import CssBaseline from '@material-ui/core/CssBaseline'

import defaultTheme from './default'

const ThemeProvider = ({theme, children}) => {
  const nextTheme = Object.assign({}, theme, defaultTheme)

  return (
    <StylesProvider injectFirst>
      <CssBaseline />
      <StyledThemeProvider theme={nextTheme}>
        <MuiThemeProvider theme={nextTheme}>{children}</MuiThemeProvider>
      </StyledThemeProvider>
    </StylesProvider>
  )
}

ThemeProvider.propTypes = {
  theme: PropTypes.object,
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
}

export default ThemeProvider

You should use the withTheme HOC as mentioned here https://material-ui.com/styles/api/#withtheme-component-component

for example:

import { styled, Button } from '@material-ui/core';

const MainButton = styled(Button)(({ theme })=> ({
  margin: theme.spacing(1),
  padding: theme.spacing(1),
  minWidth: '130px',
}));

MainButton.defaultProps = {
  variant: 'contained',
  color: 'secondary',
};

export default MainButton;

The recommended approach is to use two theme provider:

```jsx
import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import {
StylesProvider,
ThemeProvider as MuiThemeProvider,
createMuiTheme,
darken,
fade,
} from '@material-ui/core';

const myTheme = createMuiTheme();

const StyledButton = styled.button ${({ theme }) =>
padding: ${theme.spacing(1, 2)};
border: 1px solid;
cursor: pointer;
outline: 0;
border-radius: ${theme.shape.borderRadius}px;
color: ${theme.palette.primary.contrastText};
background-color: ${theme.palette.primary.main};
border-color: ${theme.palette.primary.main};
transition: ${theme.transitions.create(['background-color', 'box-shadow'])};
&:hover {
background-color: ${darken(theme.palette.primary.main, 0.1)};
border-color: ${darken(theme.palette.primary.main, 0.2)};
}
font-size: 18px;
${theme.breakpoints.up('md')} {
font-size: 16px;
}
} ;

export default function App() {
return (

Styled Components



);
}

The recommended approach is to use two theme provider:

@oliviertassinari will this approach cause performance issues?

will this approach cause performance issues?

@malik-sahab None that I'm aware of.

@oliviertassinari is there any way to use single theme provider? I would like to have determenistic classnames

@R-Oscar the class names of styled-components aren't deterministic, there is no way to make them so. Stick to JSS in this case.

@oliviertassinari I mean classes of @material-ui/core (such as MuiSvgIcon-root). According to the spec there should be only one theme provider in order to achieve that, but I would like to keep styled components in my project

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HZooly picture HZooly  路  63Comments

kybarg picture kybarg  路  164Comments

illogikal picture illogikal  路  75Comments

cfilipov picture cfilipov  路  55Comments

mnajdova picture mnajdova  路  105Comments