'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>
);
}
Related documentation:
- styled-components theme usage: https://styled-components.com/docs/advanced#theming
- StylesProvider injectFirst: https://material-ui.com/styles/api/#stylesprovider
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>;
}
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 |