CSS media queries for React

Related tags

react-media
Overview

react-media Travis npm package

react-media is a CSS media query component for React.

A <Media> component listens for matches to a CSS media query and renders stuff based on whether the query matches or not.

Installation

Using npm:

$ npm install --save react-media

Then, use as you would anything else:

// using ES modules
import Media from 'react-media';

// using CommonJS modules
var Media = require('react-media');

The UMD build is also available on unpkg:

<script src="https://unpkg.com/react-media"></script>

You can find the library on window.ReactMedia.

Hooks are coming soon!

Hooks are available in 2.X branch.

Install [email protected] to get it.

useMedia accepts a single options argument to handle both single and multiple queries, so the same properties as Media are available (except of course render and children props).

Simple usage with multiple queries:

import { useMedia } from 'react-media';

const GLOBAL_MEDIA_QUERIES = {
    small: "(max-width: 599px)",
    medium: "(min-width: 600px) and (max-width: 1199px)",
    large: "(min-width: 1200px)"
};
const matches = useMedia({ queries: GLOBAL_MEDIA_QUERIES });

const marginBottom = matches.large ? 0 : 10;

With single query :

import { useMedia } from 'react-media';

const isSmallScreen = useMedia({ query: "(max-width: 599px)" });

Basic usage

queries

Render a <Media> component with a queries prop whose value is an object, where each value is a valid CSS media query. The children prop should be a function whose argument will be an object with the same keys as your queries object, and whose values are booleans indicating whether each query matches.

import React, { Fragment } from 'react';
import Media from 'react-media';

class App extends React.Component {
  render() {
    return (
      <div>
        <Media queries={{
          small: "(max-width: 599px)",
          medium: "(min-width: 600px) and (max-width: 1199px)",
          large: "(min-width: 1200px)"
        }}>
          {matches => (
            <Fragment>
              {matches.small && <p>I am small!</p>}
              {matches.medium && <p>I am medium!</p>}
              {matches.large && <p>I am large!</p>}
            </Fragment>
          )}
        </Media>
      </div>
    );
  }
}

query

Alternatively, if you only need to match against a single media query, the query prop provides a less-verbose approach. More documentation about the difference between query and queries can be found below.

import React, { Fragment } from 'react';
import Media from 'react-media';

class App extends React.Component {
  render() {
    return (
      <div>
        <Media query="(max-width: 599px)" render={() =>
          (
            <p>I am small!</p>
          )}
        />
      </div>
    );
  }
}

query vs queries

The queries prop was added to allow for multiple media queries to be matched without excessive nesting or other workarounds. The query prop was retained out of recognition that a single query covers many use cases, and there is already a lot of usage that would be a pain to migrate.

The salient points:

  • You cannot use them together: if you do, the component will throw an error. This is to avoid confusion around precedence.
  • The render methods differ slightly: for the queries prop, the render and child JSX methods will render if at least one of the given queries is matched. The query prop renders if the given query matches.

queries

In addition to passing a valid media query string, the queries prop will also accept an object of objects whose forms are similar to React's built-in support for inline style objects in e.g. <div style>. These objects are converted to CSS media queries via json2mq.

import React from 'react';
import Media from 'react-media';

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>These two Media components are equivalent</h1>

        <Media queries={{ small: { maxWidth: 599 } }}>
          {matches =>
            matches.small ? (
              <p>The document is less than 600px wide.</p>
            ) : (
              <p>The document is at least 600px wide.</p>
            )
          }
        </Media>

        <Media queries={{ small: "(max-width: 599px)" }}>
          {matches =>
            matches.small ? (
              <p>The document is less than 600px wide.</p>
            ) : (
              <p>The document is at least 600px wide.</p>
            )
          }
        </Media>
      </div>
    );
  }
}

Keys of media query objects are camel-cased and numeric values automatically get the px suffix. See the json2mq docs for more examples of queries you can construct using objects.

Render props

There are three props which allow you to render your content. They each serve a subtly different purpose.

prop description example
render Only invoked when at least one of the queries matches. This is a nice shorthand if you only want to render something for a matching query. <Media queries={{ foo: ... }} render={() => <p>I matched!</p>} />
children (function) Receives an object of booleans whose keys are the same as the queries prop, indicating whether each media query matched. Use this prop if you need to render different output for each of specified queries. <Media queries={{ foo: ... }}>{matches => matches.foo ? <p>I matched!</p> : <p>I didn't match</p>}</Media>
children (react element) If you render a regular React element within <Media>, it will render that element when at least one of the queries matches. This method serves the same purpose as the render prop, however, you'll create component instances regardless of whether the queries match or not. Hence, using the render prop is preferred (more info). <Media queries={{ ... }}><p>I matched!</p></Media>

query

In addition to passing a valid media query string, the query prop will also accept an object, similar to React's built-in support for inline style objects in e.g. <div style>. These objects are converted to CSS media queries via json2mq.

import React from 'react';
import Media from 'react-media';

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>These two Media components are equivalent</h1>

        <Media query={{ maxWidth: 599 }}>
          {matches =>
            matches ? (
              <p>The document is less than 600px wide.</p>
            ) : (
              <p>The document is at least 600px wide.</p>
            )
          }
        </Media>

        <Media query="(max-width: 599px)">
          {matches =>
            matches ? (
              <p>The document is less than 600px wide.</p>
            ) : (
              <p>The document is at least 600px wide.</p>
            )
          }
        </Media>
      </div>
    );
  }
}

Keys of media query objects are camel-cased and numeric values automatically get the px suffix. See the json2mq docs for more examples of queries you can construct using objects.

Render props

There are three props which allow you to render your content. They each serve a subtly different purpose.

prop description example
render Only invoked when the query matches. This is a nice shorthand if you only want to render something for a matching query. <Media query="..." render={() => <p>I matched!</p>} />
children (function) Receives a single boolean element, indicating whether the media query matched. Use this prop if you need to render something when the query doesn't match. <Media query="...">{matches => matches ? <p>I matched!</p> : <p>I didn't match</p>}</Media>
children (react element) If you render a regular React element within <Media>, it will render that element when the query matches. This method serves the same purpose as the render prop, however, you'll create component instances regardless of whether the query matches or not. Hence, using the render prop is preferred (more info). <Media query="..."><p>I matched!</p></Media>

onChange

You can specify an optional onChange prop, which is a callback function that will be invoked when the status of the media queries changes. This can be useful for triggering side effects, independent of the render lifecycle.

import React from 'react';
import Media from 'react-media';

class App extends React.Component {
  render() {
    return (
      <div>
        <Media
          query={{ small: "(max-width: 599px)" }}
          onChange={matches =>
            matches.small
              ? alert('The document is less than 600px wide.')
              : alert('The document is at least 600px wide.')
          }
        />
      </div>
    );
  }
}

Server-side rendering (SSR)

If you render a <Media> component on the server, it will match by default. You can override the default behavior by setting the defaultMatches prop.

When rendering on the server you can use the defaultMatches prop to set the initial state on the server to match whatever you think it will be on the client. You can detect the user's device by analyzing the user-agent string from the HTTP request in your server-side rendering code.

initialState = {
  device: 'mobile' // add your own guessing logic here, based on user-agent for example
};

<div>
  <Media
    queries={{ medium: "(max-width: 500px)" }}
    defaultMatches={{ medium: state.device === 'mobile' }}
    render={() => <Text>Render me below medium breakpoint.</Text>}
  />

  <Media
    queries={{ medium: "(min-width: 501px)" }}
    defaultMatches={{ medium: state.device === 'desktop' }}
    render={() => <Text>Render me above medium breakpoint.</Text>}
  />
</div>;

targetWindow

An optional targetWindow prop can be specified if you want the queries to be evaluated against a different window object than the one the code is running in. This can be useful if you are rendering part of your component tree to an iframe or a popup window. See this PR thread for context.

About

react-media is developed and maintained by React Training. If you're interested in learning more about what React can do for your company, please get in touch!

Issues
  • recommended solution for multiple MQs

    recommended solution for multiple MQs

    Hi,

    what's the current solution for multiple MQs? Multiple media components? How should I compose something like that?

    A solution like this feels right to me:

          <Media
            query={{
              sm: {
                minWidth: theme.sizes.z5,
              },
              md: {
                minWidth: theme.sizes.z10,
              },
            }}
          >
            {({ sm, md }) => (
               <div>
                   { sm && <span>I am small</span> }
                   { md && <span> I am medium</span> }
               </div>
            );
            }
          </Media>
    

    at small would render as:

    <div>
       <span>I am small</span>
    </div>
    

    and at medium:

    <div>
        <span>I am small</span>
        <span>I am medium</span>
    </div>
    

    Thoughts?

    opened by VinSpee 24
  • How to set window size in jest test?

    How to set window size in jest test?

    How should I setup a test where a different component is rendered depending on screen size?

    This is the component:

    <Media query={`(max-width: ${theme.screenSizes.sm.max}px)`}>
      {matches => (matches ? this.renderMobileView() : this.renderDesktopView())}
    </Media>
    

    It only executes renderDesktopView but I'd like to also test this.renderMobileView(). I've added this to my test global.window.innerWidth = 300; with no success

    opened by grantspilsbury 16
  • removing prop types causes issues

    removing prop types causes issues

    My app started having issues since #112 when I run it in prod mode. Even if the prop type verifications aren't run, some things rely on the prop types of a component to work properly (such as https://github.com/ngReact/ngReact).

    Also, I have a component that wraps the Media component and reuses some of its proptypes like this

    MediaQueryPhoneAndTablet.propTypes = {
      children: Media.propTypes.children,
      render: Media.propTypes.render
    };
    

    which I think is a valid use of proptypes.

    My thought is while it can save a few bytes, a library should not be removing its proptypes and if an app wants that to be done, it's up to the app to do it.

    opened by bdwain 14
  • Errors after upgrading from 1.8 to 1.9

    Errors after upgrading from 1.8 to 1.9

    I get a bunch of runtime errors with version 1.9.0

    Error: Cannot find module "@babel/runtime/helpers/esm/inheritsLoose"
    
    Module not found: Error: Can't resolve '@babel/runtime/helpers/esm/assertThisInitialized' in ...
    
    Module not found: Error: Can't resolve '@babel/runtime/helpers/esm/defineProperty' in ...
    
    Module not found: Error: Can't resolve '@babel/runtime/helpers/esm/inheritsLoose' in ...
    
    opened by gersomvg 13
  • Two-pass render on the client

    Two-pass render on the client

    Thanks for this great library!

    I recently had an issue while rehydrating server side rendered markup that contained a react-media component. I'm pretty sure it was because the server side rendered markup was the desktop version and on the client the component immediately rendered the mobile markup when the respective media query matches.

    With React 16 it's no longer mandatory to have a 100% matching markup when rehydrating; React will try to patch the DOM as best as it can. In practice this can lead to some problems though if the DOM is really different – resulting in an incosistent DOM that is a mix of the desktop and the mobile markup.

    The React docs suggest a two-pass render for such scenarios that will avoid the problem:

    If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a state variable like this.state.isClient, which you can set to true in componentDidMount(). This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. Note that this approach will make your components slower because they have to render twice, so use it with caution.

    Maybe it could be helpful to move calling this.updateMatches() from cWM to cDM. This is a disadvantage for clientside-only apps though, as it could add a potentially unnecessary render.

    One strategy could be to remove the default for the defaultMatches prop. As this property is only needed for server side rendering, we could invoke the two-phase render only when this prop is actively provided by the user.

    What do you think?

    opened by amannn 13
  • Pre-configured queries for common devices?

    Pre-configured queries for common devices?

    Would it be useful for us to provide pre-configured queries for common devices? If so, what would be the best way to expose it?

    The folks over at @CSS-Tricks have compiled a nice list of media queries for standard devices that I thought we could start with. Maybe we could provide a bunch of pre-configured <Media> components that target these devices.

    <iPhone6Media>
    {matches => matches ? (
      <p>You're on an iPhone 6</p>
    ) : (
      <p>You're using something else</p>
    )
    </iPhone6Media>
    

    @ryanflorence Thoughts?

    opened by mjackson 13
  • Thoughts on server side rendering

    Thoughts on server side rendering

    This is intended to share some thoughts, and is somewhat related to #13.

    My goal is for desktop specific code not to be downloaded/evaluated on mobile devices and vice versa. This is something that I think would present a significant boost to initial load time for many websites.

    Now, a combination of this library and react-loadable would work perfectly fine, if server side rendering is not a requirement. Implementing this combination naively results in both mobile as well as desktop components being rendered serverside, which in turns results in a mismatch on the client. Actually, my current implementation (without this library), involves always rendering both components, and using CSS media queries to hide the irrelevant ones.

    I understand that it's fundamentally impossible to perform media queries serverside. However, I think we should be able to do a better job than just rendering everything, always. I'm thinking of using information from the User Agent string as a heuristic to guess which elements to render.

    Of course, this approach will inevitably result in mismatches in some cases, for example: User agent signals "mobile", but the device is large enough to show the desktop version according to the media queries. But I think accepting mismatches in these edge cases is worth the speedup in most of the cases.

    I didn't dive into implementation details, because I'd like others to chime in, and tell me if they think it's a horrible idea before I'd invest :stuck_out_tongue:

    opened by edorivai 13
  • Create typings.d.ts

    Create typings.d.ts

    This is the TypeScript typing that we're using internally. Please let me know if changes are required.

    opened by edorivai 12
  • Nested media queries cause state update on unmounted component

    Nested media queries cause state update on unmounted component

    opened by gersomvg 11
  • Cutting releases v1.9 and v2

    Cutting releases v1.9 and v2

    Hey @mjackson :wave:

    tl;dr

    • I think master is ready to be published as 1.9.
    • Could you please review the changes in next?
    • If you've given your :+1: for next, I'll go and polish the docs

    A bit of an update on the current state of the repo. I've merged most of the outstanding PRs into either master or next. I think master should be publishable as a minor version bump, as we've only added Typescript definitions (#76) and the onChange callback (#95). Docs look good, and I've prepared the CHANGES.md, you just have to add the release date.

    I don't think next is ready for deployment yet, as I'd like to do a cleanup of the docs. We've accumulated some new features over time, and while they've been added to the docs, I feel the docs now lack cohesion. Moreover, there's an outstanding PR which should improve the state of SSR (mainly preventing nasty edge-case bugs).

    After we complete those things on next, we could release a v2-alpha. What do you think?

    opened by edorivai 10
  • kotlin wrapper

    kotlin wrapper

    trying to repeat https://gitlab.com/blewpri/react-master-detail in kotlin react media been used in it https://gitlab.com/blewpri/react-master-detail/-/blob/master/src/components/MasterDetail/MasterDetail.tsx#L24 seems like currently no kotlin wrapper about react-media, just want to ask before writing my own, may be it exists somewhere or possible add this wrapper to the react-media project?

    opened by theromis 0
  • query and queries prop

    query and queries prop

    Attribute queries for is not working in 1.8.0 version. I can use query only. If i pass query object e.g. { small: "...media query...", medium: "...media query..."} (as given in documentation), it throws an error. When pass queries, query prop is still undefined and throws an error.

    opened by aplaskevich 1
  • Two-pass rendering is broken in the hooks implementation

    Two-pass rendering is broken in the hooks implementation

    See comment here: https://github.com/ReactTraining/react-media/issues/110#issuecomment-647536404

    In my head this points to a need for a test of two-pass rendering behavior, comparing the states of:

    1. server-side render
    2. first client-side pass (i.e. what would happen during hydration, before didMount/useEffect runs)
    3. second client-side pass

    I'm pretty sure this is the set of expectations:

    • if defaultMatches is set, the first two would match and the third would not
    • if defaultMatches is not set, the first clientside pass should be complete
    • if defaultMatches is set and we're only on the client, we should get two renders.

    Please correct me if the above is incorrect.

    opened by tstirrat15 10
  • Improve docs and tests for useMedia hook

    Improve docs and tests for useMedia hook

    @tstirrat15 implemented the useMedia() hook in #149 :tada:

    Two minor improvements that are left open:

    • [ ] Add tests for the hook
    • [x] Add documentation on how to use the hook
    • [x] Add types to index.d.ts

    Any help is appreciated! :pray:

    opened by edorivai 8
  • Media tries to update unmounted component

    Media tries to update unmounted component

    I’m getting the following warning from a Media-Component which implements a min-width media query: „Can't perform a React state update on an unmounted component“.

    The warning is thrown when the component is already unmounted and the user resizes the window. It seems as if the event-listener which updates the matches-state is still alive after unmounting.

    When inspecting the code I wondered why the initialize-function of Media.js is called two times (1. in constructor, 2. in componentDidMount). Doesn’t this behaviour ends up in eventListeners that will never be removed since in componentWillUnmount only the listeners created in the second call of initialize will be eleminiated?

    I’m currently using react-media in version 1.10.0

    opened by jonask94 19
  • v1.10 and v2 umbrella

    v1.10 and v2 umbrella

    Update (March 17th, 2019)

    As described in detail in #123, I'm seriously considering publishing the current changes under a minor version bump: 1.10. The bulk of the preparations for this have already been done in #123.

    The next step would be to implement a v2 which uses hooks for the core functionality. I expect a hooks implementation could simplify some of the internals, and would simultaneously allow us to ship a hook as part of the API.

    ~2.0~ 1.10

    • [x] change query prop to queries (#72)
    • [x] two-pass render + migrate to componentDidMount (solves #81, #91, #109, PR: #96)
    • [x] run tests in <Strict> mode (#115)
    • [x] merge #123
    • [x] polish the docs (#119)
    • [x] publish a prerelease, and have some people test it out in their production apps

    ~2.1~ 2.0 (now available as [email protected])

    • ~implement a hooks API, exposed as react-media/hooks~
    • [x] reimplement the core functionality using hooks, expose a useMedia hook
    • [x] implement a <Media> component, which is compatible with v1.10, but uses said hook internally

    I propose exposing Media as the default export and exporting the hook as a named export:

    import Media, { useMedia } from 'react-media';
    

    This would allow people to seamlessly upgrade to v2, without having to change existing code. There's also not really any use in splitting things up, since the Media component will be very small (just a wrapper around the hook), and it will use the hook under the hood. So I don't expect us splitting up the files will result in significant bundle size savings.

    opened by edorivai 43
Releases(v1.8.0)
  • v1.8.0(Feb 8, 2018)

  • v1.8.0-rc.1(Feb 8, 2018)

  • v1.6.1(Jul 14, 2017)

  • v1.6.0(Jul 11, 2017)

    This release adds the <Media defaultMatches> prop that should help people doing SSR (see #46 for discussion).

    It also uses the prop-types package instead of React.PropTypes which is deprecated in React version 15.5.

    Source code(tar.gz)
    Source code(zip)
Owner
React Training
High-quality open source software from React Training
React Training
🌊🐷 Utility for generalized composition of React components

???? Utility for generalized composition of React components

Enki 279 Oct 4, 2021
Declarative hotkey and focus area management for React

React HotKeys A declarative library for handling hotkeys and focus areas in React applications. Upgrading from 1.*.* ? See the upgrade notes. Looking

Aleck Greenham 1.9k Oct 3, 2021
Easily create presentation board using React

React Speaker Board Easily create presentation board using React. Quick Usage It install react-speaker-board running this comand. $ yarn add react-spe

nappa 6 Oct 14, 2021
HTML to React parser that works on both the server (Node.js) and the client (browser):

HTML to React parser that works on both the server (Node.js) and the client (browser):

Mark 1k Oct 19, 2021
A QRCode component for use with React.

qrcode.react A React component to generate QR codes. Installation npm install qrcode.react Usage var React = require('react'); var QRCode = require('q

Paul O’Shannessy 2.6k Oct 15, 2021
A lightweight react library that converts raw HTML to a React DOM structure.

A lightweight react library that converts raw HTML to a React DOM structure.

Arve Knudsen 652 Oct 17, 2021
📏 A resizable component for React.

?? A resizable component for React.

bokuweb 1.5k Oct 17, 2021
React-Godfather aims to explore an alternative mental model for function components.

React-Godfather "Look ma, no Hooks!" React-Godfather aims to explore an alternative mental model for function components. It adds a thin layer between

John Kapolos 17 Sep 20, 2021
Extended utils for ⚛️ React.Children data structure that adds recursive filter, map and more methods to iterate nested children.

React Children Utilities Recursive and extended utils for React children opaque data structure. Installation Available as a package and can be added t

Fernando Pasik 183 Oct 5, 2021
React Refresh Token with JWT and Axios Interceptors example

Buid React JWT Refresh Token example with Axios Interceptors - Refresh Token in React.js, Axios silent refresh JWT token example

null 18 Sep 30, 2021
The next generation state management library for React

The next generation state management library for React

Bytedance Inc. 150 Sep 18, 2021
iOS Today Widget in React Native

React Native Today Widget Experimental library investigating limits of implementation iOS App Extensions using React Native. Sample result from Comple

Matěj Kříž 343 Oct 3, 2021
🤖 React Native Android widgets bridged to JS, a proof of concept

React Native Android Widget Proof Of Concept ?? Using React Native and having Android widgets is possible. Create buttons in Java / Android XML to tri

Netbeast 186 Sep 21, 2021
A component for React that utilizes the Counterpart module to provide multi-lingual/localized text content.

React Translate Component Translate is a component for React that utilizes the Counterpart module and the Interpolate component to provide multi-lingu

Martin Andert 325 Apr 14, 2021
A Fetch Library Support React New Suspense SSR

use-suspense-fetch A data fetching library for React Suspense. inspired by use-asset Feature use LRU Cache support create custom cache support React 1

Snake 6 Jul 12, 2021
A simple Facebook Chat Head like bubble for react native

react-native-floating-bubble A simple Facebook Chat Head like bubble for react native. Special thanks to bubble-for-android because this is just react

null 109 Oct 14, 2021
Utility Components for determining whether elements are in the center of the screen.

@n1ru4l/react-in-center-of-screen Utility Components for determining whether elements are in the center of the screen. Codesandbox Quick Demo: https:/

Laurin Quast 12 May 29, 2021
redis like key-value state management solution for React

jedisdb redis like key-value state management solution for React Reactive. Redux alternative. Simple and powerful global state management system, acce

Hassan 10 Oct 16, 2021
React-Native library for the WidgetKit framework. Integrate a Widget into your App 🍏📱

react-native-widgetkit React-Native Library for the iOS ?? WidgetKit framework Table of Contents ?? Introduction ??‍?? Installation ??‍ Usage ????‍??

Fasky 82 Oct 13, 2021