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 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>;
}
Alternatively, you can use a callback function, accepting the theme as a first argument:
import useMediaQuery from '@material-ui/core/useMediaQuery';
function MyComponent() {
const matches = useMediaQuery(theme => theme.breakpoints.up('sm'));
return <span>{`theme.breakpoints.up('sm') matches: ${matches}`}</span>;
}
⚠️ There is no default theme support, you have to inject it in a parent theme provider.
Using JavaScript syntax
You can use json2mq 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 to emulate it.
⚠️ Server-side rendering and client-side media queries are fundamentally at odds. Be aware of the tradeoff. The support can only be partial.
Try relying on client-side CSS media queries first. For instance, you could use:
Testing
Similar to the server-side case, you need an implementation of matchMedia in your test environment.
For instance, jsdom doesn't support it yet. You should polyfill it. We recommend using css-mediaquery to emulate it.
import mediaQuery from 'css-mediaquery';
function createMatchMedia(width) {
return query => ({
matches: mediaQuery.match(query, { width }),
addListener: () => {},
removeListener: () => {},
});
}
describe('MyTests', () => {
beforeAll(() => {
window.matchMedia = createMatchMedia(window.innerWidth);
});
});
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:
API
useMediaQuery(query, [options]) => matches
Arguments
query
(String | Function): A string representing the media query to handle or a callback function accepting the theme (in the context) that returns a string.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 props
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>;
}