Skip to content


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(
      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:


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:

 * 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
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'
width: xs


useMediaQuery(query, [options]) => matches


  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 You can provide a global ponyfill using custom props on the theme. Check the server-side rendering example.


matches: Matches is true if the document currently matches the media query and false when it does not.


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>;