useMediaQuery
This is a CSS media query hook for React. It listens for matches to a CSS media query. It allows the rendering of components based on whether the query matches or not.
Some of the key features:
- โ๏ธ It has an idiomatic React API.
- ๐ It's performant, it observes the document to detect when its media queries change, instead of polling the values periodically.
- ๐ฆ 1 kB gzipped.
- ๐ It's an alternative to react-responsive and react-media that aims for simplicity.
- ๐ค It supports Server-side rendering.
Simple media query
You should provide a media query to the first argument of the hook.
The media query string can by any valid CSS media query, e.g. 'print'
.
import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';
export default function SimpleMediaQuery() {
const matches = useMediaQuery('(min-width:600px)');
return <span>{`(min-width:600px) matches: ${matches}`}</span>;
}
Using Material-UI's breakpoint helpers
You can use Material-UI's breakpoint helpers as follows:
import { useTheme } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
function MyComponent() {
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.up('sm'));
return <span>{`theme.breakpoints.up('sm') matches: ${matches}`}</span>;
}
Using JavaScript syntax
json2mq is used to generate media query string from a JavaScript object.
import React from 'react';
import json2mq from 'json2mq';
import useMediaQuery from '@material-ui/core/useMediaQuery';
export default function JavaScriptMedia() {
const matches = useMediaQuery(
json2mq({
minWidth: 600,
}),
);
return <span>{`{ minWidth: 600 } matches: ${matches}`}</span>;
}
Server-side rendering
An implementation of matchMedia is required on the server, we recommend using css-mediaquery.
We also encourage the usage of the useMediaQueryTheme
version of the hook that fetches properties from the theme. This way, you can provide a ssrMatchMedia
option once for all your React tree.
Migrating from withWidth()
The withWidth()
higher-order component injects the screen width of the page.
You can reproduce the same behavior with a useWidth
hook:
/**
* Be careful using this hook. It only works because the number of
* breakpoints in theme is static. It will break once you change the number of
* breakpoints. See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
*/
function useWidth() {
const theme = useTheme();
const keys = [...theme.breakpoints.keys].reverse();
return (
keys.reduce((output, key) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const matches = useMediaQuery(theme.breakpoints.only(key));
return !output && matches ? key : output;
}, null) || 'xs'
);
}
API
useMediaQuery(query, [options]) => matches
Arguments
query
(String): A string representing the media query to handle.options
(Object [optional]):options.defaultMatches
(Boolean [optional]): Aswindow.matchMedia()
is unavailable on the server, we return a default matches during the first mount. The default value isfalse
.options.noSsr
(Boolean [optional]): Defaults tofalse
. In order to perform the server-side rendering reconciliation, it needs to render twice. A first time with nothing and a second time with the children. This double pass rendering cycle comes with a drawback. It's slower. You can set this flag totrue
if you are not doing server-side rendering.options.ssrMatchMedia
(Function [optional]) You might want to use an heuristic to approximate the screen of the client browser. For instance, you could be using the user-agent or the client-hint https://caniuse.com/#search=client%20hint. You can provide a global ponyfill usingcustom properties
on the theme. Check the server-side rendering example.
Returns
matches
: Matches is true
if the document currently matches the media query and false
when it does not.
Examples
import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';
export default function SimpleMediaQuery() {
const matches = useMediaQuery('print');
return <span>{`@media (min-width:600px) matches: ${matches}`}</span>;
}