'Media Queries in Material-UI Using Styled-Components

Material UI has a nice set of built-in media queries: https://material-ui.com/customization/breakpoints/#css-media-queries

Material UI also allows us to use Styled-Components with Material UI: https://material-ui.com/guides/interoperability/#styled-components

I want to know how to combine the two together. That is, how can I make media queries using Styled Components and Material-UI's built-in breakpoints?

Thanks.

UPDATE:

Here is an example of what I am trying to do:

import React, { useState } from 'react'
import styled from 'styled-components'


import {
  AppBar as MuiAppBar,
  Drawer as MuiDrawer,
  Toolbar,
} from '@material-ui/core'


const drawerWidth = 240

const AdminLayout = ({ children }) => {

  return (
    <BaseLayout>
      <AppBar position="static">
        <Toolbar>
          TOOLBAR
        </Toolbar>
      </AppBar>
      <Drawer>
        DRAWER
      </Drawer>
      {children}
    </BaseLayout>
  )
}

AdminLayout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default AdminLayout

// ------- STYLES -------
const AppBar = styled(MuiAppBar)`
  /* Implement appBar styles from useStyles */
`

const Drawer = styled(MuiDrawer)`
  /* Implement drawer styles from useStyles */
`

// STYLES THAT I WANT TO CONVERT TO STYLED-COMPONENTS
const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
  },
  drawer: {
    [theme.breakpoints.up('sm')]: {
      width: drawerWidth,
      flexShrink: 0,
    },
  },
  appBar: {
    [theme.breakpoints.up('sm')]: {
      width: `calc(100% - ${drawerWidth}px)`,
      marginLeft: drawerWidth,
    },
  },
  toolbar: theme.mixins.toolbar,
}))


Solution 1:[1]

Below is an example showing one way of leveraging the Material-UI theme breakpoints with styled-components. This is passing the Material-UI theme to the styled-components ThemeProvider in order to make it available as a prop within the styles. The example also uses StylesProvider with the injectFirst prop so that the Material-UI styles will occur at the beginning of the <head> rather than the end, so that the styled-components styles occur after the Material-UI styles and therefore win when specificity is otherwise equal.

import React from "react";
import styled, { ThemeProvider as SCThemeProvider } from "styled-components";
import { useTheme, StylesProvider } from "@material-ui/core/styles";
import MuiAppBar from "@material-ui/core/AppBar";

const AppBar = styled(MuiAppBar)`
  background-color: red;
  ${props => props.theme.breakpoints.up("sm")} {
    background-color: orange;
  }
  ${props => props.theme.breakpoints.up("md")} {
    background-color: yellow;
    color: black;
  }
  ${props => props.theme.breakpoints.up("lg")} {
    background-color: green;
    color: white;
  }
`;
export default function App() {
  const muiTheme = useTheme();
  return (
    <StylesProvider injectFirst>
      <SCThemeProvider theme={muiTheme}>
        <AppBar>Sample AppBar</AppBar>
      </SCThemeProvider>
    </StylesProvider>
  );
}

Edit MUI theme breakpoints with styled-components

Related documentation:

Solution 2:[2]

If you are using the "Style Objects" approach (i.e., "JavaScript") to styled-components, then this is the way to achieve that same outcome. This builds on top of what Ryan Cogswell mentioned earlier.

Some might prefer this if switching over from another CSS-in-JS system (like Material-UI's built-in JSS). Also, the "Style Objects" approach only requires you to bring in props one time as opposed to using the props variable on any line. It's good to have choices. ?

Style Object

const AppBar = styled(MuiAppBar)((props) => ({
  backgroundColor: red;

  [props.theme.breakpoints.up("sm")]: {
    backgroundColor: orange,
  },
  [props.theme.breakpoints.up("md")]: {
    backgroundColor: yellow,
    color: black,
  },
  [props.theme.breakpoints.up("lg")]: {
    backgroundColor: green,
    color: white,
  },
}));

Style Object, but more concise

Since we only need to access the props one time using the JavaScript approach and we only use theme in this style area, we can destructure theme from the incoming props for a bit less code.

const AppBar = styled(MuiAppBar)(({ theme }) => ({
  backgroundColor: red;

  [theme.breakpoints.up("sm")]: {
    backgroundColor: orange,
  },
  [theme.breakpoints.up("md")]: {
    backgroundColor: yellow,
    color: black,
  },
  [theme.breakpoints.up("lg")]: {
    backgroundColor: green,
    color: white,
  },
}));

Note: If you are using TypeScript and have set up your styled-components theme to match the Material-UI theme, then type safety still works as expected in either the CSS or JavaScript approach.

Solution 3:[3]

The breakpoints are provided as part of the default theme.

They are constants and won't change, therefore you can use them across the components or styled themes:

import React from 'react';
import styled from 'styled-components';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => {
  console.log('md', theme.breakpoints.up('md'));
  return {};
});

const BP = {
  MD: `@media (min-width:960px) `,
};

const Container = styled.div`
  background-color: green;

  ${({ bp }) => bp} {
    background-color: red;
  }
`;

export default function StyledComponentsButton() {
  useStyles();
  return <Container bp={BP.MD}>Example</Container>;
}

Edit Styled Components

Solution 4:[4]


const StyledDrawer = styled(Drawer)(
  ({ theme }) => `
  .MuiDrawer-paper {
    ${theme.breakpoints.up('sm')} {
      width: 370px;
    }

    ${theme.breakpoints.down('sm')} {
      width: 100vw;
    }
  }   
`)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ryan Cogswell
Solution 2 Mike Mathew
Solution 3 Dennis Vash
Solution 4 LeulAria