Media queries in Material UI components
Asked Answered
K

10

98

I am using Material UI components in a React.js project, for some reason I need customization in some components to make it responsive according to screen width.

I have added media query and pass it as style attribute in the components but not working, any idea?

I am using code like this:

const drawerWidth = {
  width: '50%',
  '@media(minWidth: 780px)' : {
    width: '80%'
  }
}

<Drawer
  .....
  containerStyle = {drawerStyle}
 >
 </Drawer>

The code is working for the web only, on mobile devices no effect. Even CSS code is not applying I've checked in the developer console. I am using Material UI version 0.18.7.

Any help would be appreciated.

PS: As per requirement I need to make some changes according to screen size using CSS.

Klaraklarika answered 23/8, 2017 at 18:34 Comment(1)
how to define in declaration block for react, can you please answer with an example ? i am quite new to React thts whyKlaraklarika
S
161

By using the breakpoints attribute of the theme, you can utilize the same breakpoints used for the Grid and Hidden components directly in your component.

API

theme.breakpoints.up(key) => media query

Arguments

key (String | Number): A breakpoint key (xs, sm, etc.) or a screen width number in pixels.

Returns media query: A media query string ready to be used with JSS.

Examples

const styles = theme => ({
  root: {
    backgroundColor: 'blue',
    [theme.breakpoints.up('md')]: {
      backgroundColor: 'red',
    },
  },
});

For more information check this out

Slavery answered 10/6, 2018 at 6:1 Comment(3)
This should be the answerGrisaille
@JasbirRana ["@media (min-height:800px)"]: { marginTop: 10 }Donets
@JasbirRana in my case I was looking at how to add the device resolution using a variable, and your comment helped me.Bluepencil
P
94

You were almost right, but you need to use min-width instead of minWidth:

const styles = {
  drawerWidth: {
    width: '50%',
    '@media (min-width: 780px)': {
      width: '80%'
    }
  }
}
Parrisch answered 2/7, 2018 at 3:57 Comment(3)
Good answer. Reference github.com/mui-org/material-ui/blob/master/packages/material-ui/… to see that the methods up() and down() output a string like shown in the answer, within the square brackets.Thirzi
['@media (min-width:780px)'] having media query inside array will give no-useless-computed-key. Used only '@media (min-width:780px)' and it works.Chronicles
This worked for me: const sx = { '@media (min-width: 780px)': { width: '80%' }}; return <Box sx={sx}>...</Box>;Fadden
G
43

You have a typo in the media query. You should use the following syntax and it will work as expected:

const drawerWidth = {
  width: '50%',
  '@media (min-width: 780px)' : {
    width: '80%'
  }
}

instead of

const drawerWidth = {
  width: '50%',
  '@media(minWidth: 780px)' : {
    width: '80%'
  }
}
Gorrian answered 11/7, 2019 at 16:45 Comment(4)
Dear @croraf, please put your answer inside a brace pair. just like this: ['@media (min-width: 780px)'], Without brace your answer doesn't work yet. Thanks.Wellhead
Thank you for suggestion. I think it worked without them. Braces are needed when there is a variable inside so it needs to be evaluated in this case it's a string so no shouldn't be needed.Gorrian
This is the right answer..Happening
This is indeed the right answer.Toolis
O
30

In MUI v5, breakpoints can be declared in sx props by specifying an object where the keys are the breakpoint names and the values are the CSS values.

You can see MUI default breakpoints here. The breakpoint names and values can be overrided using createTheme():

const theme = createTheme({
  breakpoints: {
    values: {
      xxs: 0, // small phone
      xs: 300, // phone
      sm: 600, // tablets
      md: 900, // small laptop
      lg: 1200, // desktop
      xl: 1536 // large screens
    }
  }
});
return (
  <ThemeProvider theme={theme}>
    <Box
      sx={{
        // specify one value that is applied in all breakpoints
        color: 'white',
        // specify multiple values applied in specific breakpoints
        backgroundColor: {
          xxs: "red",
          xs: "orange",
          sm: "yellow",
          md: "green",
          lg: "blue",
          xl: "purple"
        }
      }}
    >
      Box 1
    </Box>
  </ThemeProvider>
);

In the example above, xs: "orange" means set the Box color to orange if the screen width is inside xs range [300, 600).

You can also set the breakpoints using an array consists of the values from the smallest to largest breakpoint:

return (
  <ThemeProvider theme={theme}>
    <Box
      sx={{
        backgroundColor: [
          "red",
          "orange",
          // unset, screen width inside this breakpoint uses the last non-null value
          null,
          "green",
          "blue",
          "purple"
        ]
      }}
    >
      Box 2
    </Box>
  </ThemeProvider>
);

Edit 45847090/media-queries-in-material-ui-components

Originate answered 17/9, 2021 at 10:28 Comment(4)
Thanks! This is great for a concise syntax.Firn
This should be the approved answer!Contumacious
awesome solution. Just xxs breakpoint is not default, maybe remove it from the example.Pastel
It works but I suggest using Croraf's media query answer belowToolis
V
12

Similiar answer to @Lipunov's, based on @nbkhope's comment

const styles = {
  drawerWidth: {
    width: '50%',
    [theme.breakpoints.up(780)]: {
      width: '80%'
    }
  }
}
Validate answered 18/1, 2020 at 20:17 Comment(0)
C
5

I've solved this problem by doing something like this:

const dropzoneStyles = 
window.screen.availWidth < 780 ? 
{ 'width': '150px', 'height': '150px', 'border': 'none', 'borderRadius': '50%' }
: { 'width': '200px', 'height': '200px', 'border': 'none', 'borderRadius': '50%' };

and then appending it as an attribute in the Material UI element:

<Dropzone style={dropzoneStyles} onDrop={this.handleDrop.bind(this)}>

So the key is to find out the window screen using window.screen.availWidth. And you would be doing this in the render() function. Hope that helps!

Casto answered 30/11, 2017 at 18:19 Comment(0)
G
5

In my case I just needed the breakpoint on one component and I found the createTheme approach a little bit too much. I ended using useMediaQuery and useTheme.

I see that with useMEdiaQuery you can be quite granular

import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';

const Component = () => {
  const theme = useTheme();
  const matchesSM = useMediaQuery(theme.breakpoints.down('sm'));
  const matchesMD = useMediaQuery(theme.breakpoints.only('md'));
  const dynamicStyles = {
    ...matchesSM && {margin: '10px 0'},
    ...matchesMD && {margin: '20px 0'}
  }

  return (
    <Grid item xs={12} md={4} sx={{...dynamicStyles}}>
      <div>Children</div>
    </Grid>
  )
}
Graphemics answered 6/5, 2022 at 17:2 Comment(0)
P
3

In the style property on React you can only define properties that you can define in a normal DOM element (You can't include media queries for example)

The way you can include media queries for that component would be passing a class name to the Drawer Component

<Drawer containerClassName="someClass" /> 

And then in a CSS file you do something like this

@media(min-width: 780px){
  .someClass {
    width: 50%!important;
  }
}
Pinup answered 23/8, 2017 at 18:59 Comment(6)
That i know, but this does't make any sense, it will just add Css Class to that container no to the inner element or container where needed, isn't it ?.Klaraklarika
Sorry It should be containerClassName instead of className (Updating the answer), that should add the class to the drawer container and then you can easily modifed its width with CSSPinup
I just used this (drawer) as example, in none of the case my media queries are working.Klaraklarika
It seems like the drawer add inline-styles to the container so that styles have more precedence, you can try with !important at the end of the widthPinup
yes , i did agree that it works, but only on the parent container not on child of that container. also this is not a preferred way anyways.Klaraklarika
This answer should be deleted, it relies on an external css file instead of properly using the theming break points. No need to use the framework if you just going to use vanilla css.Bathos
C
2

CSS media queries are the idiomatic approach to make your UI responsive. The theme provides five styles helpers to do so:

theme.breakpoints.up(key)
theme.breakpoints.down(key)
theme.breakpoints.only(key)
theme.breakpoints.not(key)
theme.breakpoints.between(start, end)

In the following stress test, you can update the theme color and the background-color property live:

const styles = (theme) => ({
  root: {
    padding: theme.spacing(1),
    [theme.breakpoints.down('md')]: {
      backgroundColor: theme.palette.secondary.main,
    },
    [theme.breakpoints.up('md')]: {
      backgroundColor: theme.palette.primary.main,
    },
    [theme.breakpoints.up('lg')]: {
      backgroundColor: green[500],
    },
  },
});
<Root>
  <Typography>down(md): red</Typography>
  <Typography>up(md): blue</Typography>
  <Typography>up(lg): green</Typography>
</Root>

Know more

Catharinecatharsis answered 1/2, 2022 at 11:52 Comment(0)
C
1

Create a variable and then use that variable anywhere in the function

import React from 'react';
import { createMuiTheme, ThemeProvider, useTheme } from '@materialui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
    

function MyComponent() {
  const theme = useTheme();
  const matches = useMediaQuery(theme.breakpoints.up('sm')); // Variable for media query 
  return <span hidden={matches}>Hidden on screen size greater then sm </span>;
}

const theme = createMuiTheme();

export default function ThemeHelper() {
  return (
    <ThemeProvider theme={theme}>
      <MyComponent />
    </ThemeProvider>
  );
}
Chandelier answered 4/12, 2020 at 16:28 Comment(1)
Read Material ui doc material-ui.com/components/use-media-queryChandelier

© 2022 - 2024 — McMap. All rights reserved.