Konzy262
Konzy262

Reputation: 3117

'Undefined' when attempting to pass MaterialUI theme props to styled components

I'm attempting to access my Material-UI theme props within a styled component, however I keep getting...

TypeError: Cannot read property 'primary' of undefined or similar errors in the browser.

Here is my custom theme (index.ts)

import { createMuiTheme } from "@material-ui/core";
import { blue } from "@material-ui/core/colors";

const theme = createMuiTheme({
    palette: {
      primary: {
        main: blue[800],
        contrastText: "#FFF"
      },
      secondary: {
        main: blue[600],
        contrastText: "#FFF"
      }
    },
    typography : {
        fontFamily: [
            "Nunito",
            "Roboto",
        ].join(",") 
    }
});

export default theme;

Here is where my theme wraps my application in the App.tsx

// Other imports
import theme from "../../app/theme/index";

const App: React.FC = () => {
    return (
        <>
            <StylesProvider injectFirst>
                <ThemeProvider theme={theme}>
                    // Routing stuff
                </ThemeProvider>
            </StylesProvider>
        </>
    );
};

export default App;

And here is where I am attempting to use my styled component

import { ListItem } from "@material-ui/core";
import React from "react";
import styled from "styled-components";

const Brand = styled(ListItem)`
    background-color: ${props => props.theme.palette.primary.dark},
    padding: ${props => props.theme.spacing(1)},
    font-size: ${props => props.theme.typography.h6.fontSize},
    font-weight: ${props => props.theme.typography.fontWeightMedium},
    color: "white",
    min-height: "64px",
    padding-left: ${props => props.theme.spacing(6)}
`;

const SidebarNew: React.FC = () => {

    return (
        <Brand button>
            // Stuff
        </Brand>
    );
};

export default SidebarNew;

This compiles but fails in the browser. What am I missing here?

If I use material-ui's built in styled like below, it appears to work, however I would prefer to use styled-components directly

const Brand = styled(ListItem)(({ theme }) => ({
    backgroundColor: theme.palette.primary.dark,
    padding: theme.spacing(1),
    fontSize: theme.typography.h6.fontSize,
    fontWeight: theme.typography.fontWeightMedium,
    color: "white",
    minHeight: 64,
    paddingLeft: theme.spacing(6)
}));

Upvotes: 2

Views: 4723

Answers (1)

Ryan Cogswell
Ryan Cogswell

Reputation: 81166

You need to use ThemeProvider from styled-components (SCThemeProvider in the example below) in addition to the Material-UI ThemeProvider; otherwise styled-components won't know about your theme.

Here is a working example:

import {
  createMuiTheme,
  StylesProvider,
  ThemeProvider
} from "@material-ui/core";
import { ThemeProvider as SCThemeProvider } from "styled-components";
import * as React from "react";
import Dashboard from "./Dashboard";
import "./styles.css";

const theme = createMuiTheme({
  palette: {
    primary: {
      main: "#1a1aff",
      contrastText: "#FFF"
    },
    secondary: {
      main: "#ff3333",
      contrastText: "#FFF"
    }
  },
  typography: {
    h5: {
      fontSize: "10px"
    }
  }
});

export default function App() {
  return (
    <StylesProvider injectFirst>
      <ThemeProvider theme={theme}>
        <SCThemeProvider theme={theme}>
          <Dashboard />
        </SCThemeProvider>
      </ThemeProvider>
    </StylesProvider>
  );
}

Edit Material-UI Theme (forked)

Upvotes: 4

Related Questions