Information
Package | react-responsive |
Description | Media queries in react for responsive design |
Browser Version | >= IE6* |
Demo |
The best supported, easiest to use react media query module.
Install
$ npm install react-responsive --save
Example Usage
With Hooks
Hooks is a new feature available in 8.0.0!
import React from 'react'
import { useMediaQuery } from 'react-responsive'
const Example = () => {
const isDesktopOrLaptop = useMediaQuery({
query: '(min-width: 1224px)'
})
const isBigScreen = useMediaQuery({ query: '(min-width: 1824px)' })
const isTabletOrMobile = useMediaQuery({ query: '(max-width: 1224px)' })
const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
const isRetina = useMediaQuery({ query: '(min-resolution: 2dppx)' })
return <div>
<h1>Device Test!</h1>
{isDesktopOrLaptop && <p>You are a desktop or laptop</p>}
{isBigScreen && <p>You have a huge screen</p>}
{isTabletOrMobile && <p>You are a tablet or mobile phone</p>}
<p>Your are in {isPortrait ? 'portrait' : 'landscape'} orientation</p>
{isRetina && <p>You are retina</p>}
</div>
}
With Components
import MediaQuery from 'react-responsive'
const Example = () => (
<div>
<h1>Device Test!</h1>
<MediaQuery minWidth={1224}>
<p>You are a desktop or laptop</p>
<MediaQuery minWidth={1824}>
<p>You also have a huge screen</p>
</MediaQuery>
</MediaQuery>
<MediaQuery minResolution="2dppx">
{/* You can also use a function (render prop) as a child */}
{(matches) =>
matches
? <p>You are retina</p>
: <p>You are not retina</p>
}
</MediaQuery>
</div>
)
API
Using Properties
To make things more idiomatic to react, you can use camel-cased shorthands to construct media queries.
For a list of all possible shorthands and value types see https://github.com/contra/react-responsive/blob/master/src/mediaQuery.ts#L9.
Any numbers given as shorthand will be expanded to px (1234
will become '1234px'
).
The CSS media queries in the example above could be constructed like this:
import React from 'react'
import { useMediaQuery } from 'react-responsive'
const Example = () => {
const isDesktopOrLaptop = useMediaQuery({ minWidth: 1224 })
const isBigScreen = useMediaQuery({ minWidth: 1824 })
const isTabletOrMobile = useMediaQuery({ maxWidth: 1224 })
const isPortrait = useMediaQuery({ orientation: 'portrait' })
const isRetina = useMediaQuery({ minResolution: '2dppx' })
return (
<div>
...
</div>
)
}
device
prop
Forcing a device with the At times you may need to render components with different device settings than what gets automatically detected. This is especially useful in a Node environment where these settings can't be detected (SSR) or for testing.
Possible Keys
orientation
, scan
, aspectRatio
, deviceAspectRatio
, height
, deviceHeight
, width
, deviceWidth
, color
, colorIndex
, monochrome
, resolution
and type
Possible Types
type
can be one of: all
, grid
, aural
, braille
, handheld
, print
, projection
, screen
, tty
, tv
or embossed
Note: The device
property always applies, even when it can be detected (where window.matchMedia exists).
import { useMediaQuery } from 'react-responsive'
const Example = () => {
const isDesktopOrLaptop = useMediaQuery(
{ minDeviceWidth: 1224 },
{ deviceWidth: 1600 } // `device` prop
)
return (
<div>
{isDesktopOrLaptop &&
<p>
this will always get rendered even if device is shorter than 1224px,
that's because we overrode device settings with 'deviceWidth: 1600'.
</p>
}
</div>
)
}
Supplying through Context
You can also pass device
to every useMediaQuery
hook in the components tree through a React Context. This should ease up server-side-rendering and testing in a Node environment, e.g:
Server-Side Rendering
import { Context as ResponsiveContext } from 'react-responsive'
import { renderToString } from 'react-dom/server'
import App from './App'
...
// Context is just a regular React Context component, it accepts a `value` prop to be passed to consuming components
const mobileApp = renderToString(
<ResponsiveContext.Provider value={{ width: 500 }}>
<App />
</ResponsiveContext.Provider>
)
...
Testing
import { Context as ResponsiveContext } from 'react-responsive'
import { render } from '@testing-library/react'
import ProductsListing from './ProductsListing'
describe('ProductsListing', () => {
test('matches the snapshot', () => {
const { container: mobile } = render(
<ResponsiveContext.Provider value={{ width: 300 }}>
<ProductsListing />
</ResponsiveContext.Provider>
)
expect(mobile).toMatchSnapshot()
const { container: desktop } = render(
<ResponsiveContext.Provider value={{ width: 1000 }}>
<ProductsListing />
</ResponsiveContext.Provider>
)
expect(desktop).toMatchSnapshot()
})
})
Note that if anything has a device
prop passed in it will take precedence over the one from context.
onChange
You can use the onChange
callback to specify a change handler that will be called when the media query's value changes.
import React from 'react'
import { useMediaQuery } from 'react-responsive'
const Example = () => {
const handleMediaQueryChange = (matches) => {
// matches will be true or false based on the value for the media query
}
const isDesktopOrLaptop = useMediaQuery(
{ minWidth: 1224 }, undefined, handleMediaQueryChange
);
return (
<div>
...
</div>
)
}
import React from 'react'
import MediaQuery from 'react-responsive'
const Example = () => {
const handleMediaQueryChange = (matches) => {
// matches will be true or false based on the value for the media query
}
return (
<MediaQuery minWidth={1224} onChange={handleMediaQueryChange}>
...
</MediaQuery>
)
}
Easy Mode
That's it! Now you can create your application specific breakpoints and reuse them easily. Here is an example:
import { useMediaQuery } from 'react-responsive'
const Desktop = ({ children }) => {
const isDesktop = useMediaQuery({ minWidth: 992 })
return isDesktop ? children : null
}
const Tablet = ({ children }) => {
const isTablet = useMediaQuery({ minWidth: 768, maxWidth: 991 })
return isTablet ? children : null
}
const Mobile = ({ children }) => {
const isMobile = useMediaQuery({ maxWidth: 767 })
return isMobile ? children : null
}
const Default = ({ children }) => {
const isNotMobile = useMediaQuery({ minWidth: 768 })
return isNotMobile ? children : null
}
const Example = () => (
<div>
<Desktop>Desktop or laptop</Desktop>
<Tablet>Tablet</Tablet>
<Mobile>Mobile</Mobile>
<Default>Not mobile (desktop or laptop or tablet)</Default>
</div>
)
export default Example
And if you want a combo (the DRY way):
import { useMediaQuery } from "react-responsive"
const useDesktopMediaQuery = () =>
useMediaQuery({ query: "(min-width: 1280px)" })
const useTabletAndBelowMediaQuery = () =>
useMediaQuery({ query: "(max-width: 1279px)" })
const Desktop = ({ children }) => {
const isDesktop = useDesktopMediaQuery()
return isDesktop ? children : null
}
const TabletAndBelow = ({ children }) => {
const isTabletAndBelow = useTabletAndBelowMediaQuery()
return isTabletAndBelow ? children : null
}
Browser Support
Out of the box
Chrome | 9 |
Firefox (Gecko) | 6 |
MS Edge | All |
Internet Explorer | 10 |
Opera | 12.1 |
Safari | 5.1 |
With Polyfills
Pretty much everything. Check out these polyfills:
Server rendering example
It's not clear from this example how server rendering works. I see that only the first media query has
values
passed in so I imagine the other ones "don't work" on the server. Right? Are the values ignored client side in a universal component? Also, is there any recommended module for pulling out those values on the server based on the user agent? I would be happy to clarify this in the readme with a PR as soon as I learn more.Not usable for server-side rendered components
This component,
MediaQuery
has a drawback when you are wrapping an isomorphic/universal react component. Just switch off JavaScript and see the components underMatchQuery
disappear. I believe the real idea behind isomorphic components is, to also be able to render them/have them available even without JavaScript. It defeats the purpose of having universal components when they fail with JS disabled.Installing v8.0.0 - Cannot find source file 'webpack:///dist/react-responsive.js'
Just installed v8.0, and currently getting this error:
[SSR] call matchMedia in componentDidMount
Currently, if you rendered a component on the server with a certain set of
values
and then the component is mount in the browser thequery
is not reevaluated against the actual environment which might lead to an incorrect result if your assumption about the user's environment during SSR was not right.We can probably fix it by adding the following to the
MediaQuery
code:Is it correct? If so I can open a PR for this change
Div inside media query not rendering on device
Hi - I had a div tag inside a media query that was being displayed correctly on the Chrome iphone emulator but when I viewed my app on a device the div was not being rendered (in Safari or Chrome, I checked both). As part of my testing I discovered that if I put a p tag (or I assume any tag) directly after the media query but before the div, the div would be correctly displayed (again, on both Safari and Chrome). So in order to see my div on a device I had to put an empty p tag before the div tag, which seems..odd. Could this be a bug? Thanks!
Using useMediaQuery with min-width does not trigger re-rendering when orientation is changed on iPhone
I'm using This library to detect the width of the screen and render different components, so this code:
... is not working for me on Safari/iPhone 10/11 either native device or simulator. Works on Android Chrome and Desktop Chrome Emulator.
Does not rerender when values changes
Tried using the new version but it's still not working. GetDerivedStateFromProps returns null even though values object changes. I think the we need to store forceStatic in the state.
when we store forcesStatic in the state it triggers a rerender if we omit it after first render on the client.
The same but without storing forceStatic in the state
Can't figure out how to test using Enzyme.
Is it possible to test React-Responsive components with Enzyme.
the key parts of my code look like this:
The test result is:
The relevant part of the output of the console.log is:
<MediaQuery minDeviceWidth={750} values={{...}} />
Indicating that Header is indeed not appearing in the render tree. However if I remove the MediaQuery and make Header a direct child of AppContainer the test passes.I imagine this is not a bug as I'm very new to Enzyme and testing components in general. Any help or examples would be appreciated.
Getting checksum was invalid error for server-side rendered component
I'm getting checksum invalid error,
warning.js:45Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
a bit large
Adding this lib to my react app, it adds 12.4KB (uglified) to my built js file (3.6KB gzipped) which seems very large for what this does. Is there perhaps one of the dependencies being mostly responsible for this bloat, that could be replaced by something else?
implement useMediaQuery hook and fix tests
Adds hooks support and References #180
MediaQuery
component anduseMediaQuery
hookuseMediaQuery
hookuseMediaQuery
API (arguments it takes and what it returns)MediaQuery
? (don't think it's a good idea, React.memo creates a HOC and diffing might be even more expensive than the time saved, it's better to leave it up to the user)shallow-equal
dependency could be avoided (I don't know how to replace it, but it's tiny and it adds a really good optimization)[Bug] Vite React - Building results in unrecognized function
Thank you for this awesome library, after recently changing from CRA to Vite for a big project, the build would fail on (see screenshot). After removing the library things started to work again. Do note - that this project is fairly sized, so it can be a result of many different parts together.
Using the following: "react-responsive": "9.0.0", "react": "18.2.0" "typescript": "4.8.4", "vite": "^3.2.3",
React Responsive doesn't work if i refresh the page
React Responsive doesn't work while on mobile
When i working on next.js project from desktop. I open the mobile preview mode and in there have no problem, but if i refresh my page in preview mode react-responsive doesn't work, thats why in production doesn't work
Example Use;
index.js
upload.js
For better explain;
When i without refresh open preview mode
But if I refresh page in preview mode it looks like this;
My package.json;
Context for server-side-rendering hard set the width
I am trying to use react-responsive to conditional rendering components base on device width. Everything worked great in client side, but for SSR I followed the documentation to use Context to pass a specific width for initial server render. However, the width that react-responsive received now hard set to the width in Context even if I resize the browser.
Component to define device base on device width:
My use for DeviceIdentifier component:
Context wrapper in _app.js
Since I set the width in the context 1440px, my BurgerMenu component is currently never rendered even if resize the browser. Anybody have any idea how to make this work both in SSR and client side?
Nextjs: Expected server HTML to contain a matching in
-
16
I have tried all the available options and all of them brings me back this same error.
Example:
<MediaQuery minDeviceWidth={1024}> <div>Desktop Only</div> </MediaQuery>
Nested responsive components that use refs results in stale elements in Safari
Hello, we use examples provided in Easy Mode section of the doc and faced the issue that reproduces in Safari (13.0.5) on Mac OS. The problem occurs when the responsive components are nested and there is some child that uses ref. Something like this (sandbox)
After resizing the window back and forward the following warning occurs:
and some elements get duplicated.
We found this issue in 8.0.3 version but it also presents in 7.0.0.