Aww yeah, Material-UI v4 is here!


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.

⚠️ useMediaQuery is unstable as hooks aren't stable yet, therefore it is exported with an unstable prefix. Please note that it depends on react@next and react-dom@next.

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.
  • 📦 Less than 700 B 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 { unstable_useMediaQuery as useMediaQuery } from '@material-ui/core/useMediaQuery';

function MyComponent() {
  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/styles';
import { unstable_useMediaQuery as 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

Server-side rendering

An implementation of matchMedia is required on the server, we recommend using css-mediaquery. We also encourage the usage of the unstable_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.

@media (min-width:600px) matches: true

Migrating from withWidth()

The withWidth() higher-order component injects the screen width of the page. You can reproduce the same behavior as follow:

function MyComponent() {
  const theme = useTheme();
  const width =
    [...theme.breakpoints.keys].reverse().reduce((output, key) => {
      const matches = useMediaQuery(theme.breakpoints.only(key));

      return !output && matches ? key : output;
    }, null) || 'xs';

  return <span>{width}</span>;
width: xs


unstable_useMediaQuery(query, [options]) => matches


  1. query (String): A string representing the media query to handle.
  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 properties 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 { unstable_useMediaQuery as useMediaQuery } from '@material-ui/core/useMediaQuery';

export default function SimpleMediaQuery() {
  const matches = useMediaQuery('print');

  return <span>{`@media (min-width:600px) matches: ${matches}`}</span>;