Moshe
Moshe

Reputation: 6991

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,
}))

Upvotes: 12

Views: 31857

Answers (6)

TorvaldsDB
TorvaldsDB

Reputation: 972

I totally agree with the answer https://stackoverflow.com/a/64047876/7262646

I get the official document Here from Mui-system which is imported by material-ui inside.

I'll paste some example here

const StatWrapper = styled('div')(
  ({ theme }) => `
  background-color: ${theme.palette.background.paper};
  box-shadow: ${theme.shadows[1]};
  border-radius: ${theme.shape.borderRadius}px;
  padding: ${theme.spacing(2)};
  min-width: 300px;
`,
);

const StatHeader = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.text.secondary};
`,
);

const StyledTrend = styled(TrendingUpIcon)(
  ({ theme }) => `
  color: ${theme.palette.success.dark};
  font-size: 16px;
  vertical-alignment: sub;
`,
);

const StatValue = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.text.primary};
  font-size: 34px;
  font-weight: ${theme.typography.fontWeightMedium};
`,
);

const StatDiff = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.success.dark};
  display: inline;
  font-weight: ${theme.typography.fontWeightMedium};
  margin-left: ${theme.spacing(0.5)};
  margin-right: ${theme.spacing(0.5)};
`,
);

const StatPrevious = styled('div')(
  ({ theme }) => `
  color: ${theme.palette.text.secondary};
  display: inline;
  font-size: 12px;
`,
);

return (
  <StatWrapper>
    <StatHeader>Sessions</StatHeader>
    <StatValue>98.3 K</StatValue>
    <StyledTrend />
    <StatDiff>18.77%</StatDiff>
    <StatPrevious>vs last week</StatPrevious>
  </StatWrapper>
);

Upvotes: 0

phoenixstudio
phoenixstudio

Reputation: 2598

The syntax may look weird, but trying this code will explain everything

const StyledDiv = styled.div`
  ${({theme}) => {
  console.log(theme.breakpoints.up('lg'));
  return "";
}}
`;
// you will see in your console
// @media (min-width:1280px)

Once you understand that theme.breakpoints.up('lg') is same as @media (min-width:1280px) everything become obvious. everytime you put theme.breakpoints.up(key) it get replaced with @media... string.

Upvotes: 1

LeulAria
LeulAria

Reputation: 605


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

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

Upvotes: -3

Mike Mathew
Mike Mathew

Reputation: 932

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.

Upvotes: 21

Ryan Cogswell
Ryan Cogswell

Reputation: 80986

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:

Upvotes: 23

Dennis Vash
Dennis Vash

Reputation: 53874

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

Upvotes: 0

Related Questions