Skip to content

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>;
}
(min-width:600px) matches: false

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>;
}
theme.breakpoints.up('sm') matches: false

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>;
}
{ minWidth: 600 } matches: false

Server-side rendering

An implementation of matchMedia is required on the server. We recommend using css-mediaquery to emulate it.

(min-width:600px) matches: true

⚠️ 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:

width: xs

API

useMediaQuery(query, [options]) => matches

Arguments

  1. 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.
  2. options (Object [optional]):
    • options.defaultMatches (Boolean [optional]): As window.matchMedia() is unavailable on the server, we return a default matches during the first mount. The default value is false.
    • options.noSsr (Boolean [optional]): Defaults to false. 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 to true 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 using custom 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>;
}