1 | # react-responsive [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url]
|
2 |
|
3 | ## Information
|
4 |
|
5 | <table>
|
6 | <tr>
|
7 | <td>Package</td><td>react-responsive</td>
|
8 | </tr>
|
9 | <tr>
|
10 | <td>Description</td>
|
11 | <td>Media queries in react for responsive design</td>
|
12 | </tr>
|
13 | <tr>
|
14 | <td>Browser Version</td>
|
15 | <td>>= IE6*</td>
|
16 | </tr>
|
17 | </tr>
|
18 | <tr>
|
19 | <td colspan='2'><a href='http://contra.io/react-responsive/'>Demo</a></td>
|
20 | </tr>
|
21 | </table>
|
22 |
|
23 | The best supported, easiest to use react media query module.
|
24 |
|
25 | ## Install
|
26 |
|
27 | ```console
|
28 | $ npm install react-responsive --save
|
29 | ```
|
30 |
|
31 | ## Example Usage
|
32 |
|
33 | ### With Hooks
|
34 |
|
35 | Hooks is a new feature available in 8.0.0!
|
36 |
|
37 | ```jsx
|
38 | import React from 'react'
|
39 | import { useMediaQuery } from 'react-responsive'
|
40 |
|
41 | const Example = () => {
|
42 | const isDesktopOrLaptop = useMediaQuery({
|
43 | query: '(min-width: 1224px)'
|
44 | })
|
45 | const isBigScreen = useMediaQuery({ query: '(min-width: 1824px)' })
|
46 | const isTabletOrMobile = useMediaQuery({ query: '(max-width: 1224px)' })
|
47 | const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
|
48 | const isRetina = useMediaQuery({ query: '(min-resolution: 2dppx)' })
|
49 |
|
50 | return <div>
|
51 | <h1>Device Test!</h1>
|
52 | {isDesktopOrLaptop && <p>You are a desktop or laptop</p>}
|
53 | {isBigScreen && <p>You have a huge screen</p>}
|
54 | {isTabletOrMobile && <p>You are a tablet or mobile phone</p>}
|
55 | <p>Your are in {isPortrait ? 'portrait' : 'landscape'} orientation</p>
|
56 | {isRetina && <p>You are retina</p>}
|
57 | </div>
|
58 | }
|
59 | ```
|
60 |
|
61 | ### With Components
|
62 |
|
63 | ```jsx
|
64 | import MediaQuery from 'react-responsive'
|
65 |
|
66 | const Example = () => (
|
67 | <div>
|
68 | <h1>Device Test!</h1>
|
69 | <MediaQuery minWidth={1224}>
|
70 | <p>You are a desktop or laptop</p>
|
71 | <MediaQuery minWidth={1824}>
|
72 | <p>You also have a huge screen</p>
|
73 | </MediaQuery>
|
74 | </MediaQuery>
|
75 | <MediaQuery minResolution="2dppx">
|
76 | {/* You can also use a function (render prop) as a child */}
|
77 | {(matches) =>
|
78 | matches
|
79 | ? <p>You are retina</p>
|
80 | : <p>You are not retina</p>
|
81 | }
|
82 | </MediaQuery>
|
83 | </div>
|
84 | )
|
85 | ```
|
86 |
|
87 | ## API
|
88 |
|
89 | ### Using Properties
|
90 |
|
91 | To make things more idiomatic to react, you can use camel-cased shorthands to construct media queries.
|
92 |
|
93 | For a list of all possible shorthands and value types see https://github.com/contra/react-responsive/blob/master/src/mediaQuery.ts#L9.
|
94 |
|
95 | Any numbers given as shorthand will be expanded to px (`1234` will become `'1234px'`).
|
96 |
|
97 | The CSS media queries in the example above could be constructed like this:
|
98 |
|
99 | ```jsx
|
100 | import React from 'react'
|
101 | import { useMediaQuery } from 'react-responsive'
|
102 |
|
103 | const Example = () => {
|
104 | const isDesktopOrLaptop = useMediaQuery({ minWidth: 1224 })
|
105 | const isBigScreen = useMediaQuery({ minWidth: 1824 })
|
106 | const isTabletOrMobile = useMediaQuery({ maxWidth: 1224 })
|
107 | const isPortrait = useMediaQuery({ orientation: 'portrait' })
|
108 | const isRetina = useMediaQuery({ minResolution: '2dppx' })
|
109 |
|
110 | return (
|
111 | <div>
|
112 | ...
|
113 | </div>
|
114 | )
|
115 | }
|
116 | ```
|
117 |
|
118 | ### Forcing a device with the `device` prop
|
119 |
|
120 | 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.
|
121 |
|
122 | #### Possible Keys
|
123 |
|
124 | `orientation`, `scan`, `aspectRatio`, `deviceAspectRatio`,
|
125 | `height`, `deviceHeight`, `width`, `deviceWidth`, `color`, `colorIndex`, `monochrome`,
|
126 | `resolution` and `type`
|
127 |
|
128 | ##### Possible Types
|
129 |
|
130 | `type` can be one of: `all`, `grid`, `aural`, `braille`, `handheld`, `print`, `projection`,
|
131 | `screen`, `tty`, `tv` or `embossed`
|
132 |
|
133 | Note: The `device` property always applies, even when it can be detected (where window.matchMedia exists).
|
134 |
|
135 | ```jsx
|
136 | import { useMediaQuery } from 'react-responsive'
|
137 |
|
138 | const Example = () => {
|
139 | const isDesktopOrLaptop = useMediaQuery(
|
140 | { minDeviceWidth: 1224 },
|
141 | { deviceWidth: 1600 } // `device` prop
|
142 | )
|
143 |
|
144 | return (
|
145 | <div>
|
146 | {isDesktopOrLaptop &&
|
147 | <p>
|
148 | this will always get rendered even if device is shorter than 1224px,
|
149 | that's because we overrode device settings with 'deviceWidth: 1600'.
|
150 | </p>
|
151 | }
|
152 | </div>
|
153 | )
|
154 | }
|
155 | ```
|
156 |
|
157 | #### Supplying through Context
|
158 |
|
159 | You can also pass `device` to every `useMediaQuery` hook in the components tree through a React [Context](https://reactjs.org/docs/context.html).
|
160 | This should ease up server-side-rendering and testing in a Node environment, e.g:
|
161 |
|
162 | ##### Server-Side Rendering
|
163 |
|
164 | ```jsx
|
165 | import { Context as ResponsiveContext } from 'react-responsive'
|
166 | import { renderToString } from 'react-dom/server'
|
167 | import App from './App'
|
168 |
|
169 | ...
|
170 | // Context is just a regular React Context component, it accepts a `value` prop to be passed to consuming components
|
171 | const mobileApp = renderToString(
|
172 | <ResponsiveContext.Provider value={{ width: 500 }}>
|
173 | <App />
|
174 | </ResponsiveContext.Provider>
|
175 | )
|
176 | ...
|
177 | ```
|
178 |
|
179 | ##### Testing
|
180 |
|
181 | ```jsx
|
182 | import { Context as ResponsiveContext } from 'react-responsive'
|
183 | import { render } from '@testing-library/react'
|
184 | import ProductsListing from './ProductsListing'
|
185 |
|
186 | describe('ProductsListing', () => {
|
187 | test('matches the snapshot', () => {
|
188 | const { container: mobile } = render(
|
189 | <ResponsiveContext.Provider value={{ width: 300 }}>
|
190 | <ProductsListing />
|
191 | </ResponsiveContext.Provider>
|
192 | )
|
193 | expect(mobile).toMatchSnapshot()
|
194 |
|
195 | const { container: desktop } = render(
|
196 | <ResponsiveContext.Provider value={{ width: 1000 }}>
|
197 | <ProductsListing />
|
198 | </ResponsiveContext.Provider>
|
199 | )
|
200 | expect(desktop).toMatchSnapshot()
|
201 | })
|
202 | })
|
203 | ```
|
204 |
|
205 | Note that if anything has a `device` prop passed in it will take precedence over the one from context.
|
206 |
|
207 | ### `onChange`
|
208 |
|
209 | You can use the `onChange` callback to specify a change handler that will be called when the media query's value changes.
|
210 |
|
211 | ```jsx
|
212 | import React from 'react'
|
213 | import { useMediaQuery } from 'react-responsive'
|
214 |
|
215 | const Example = () => {
|
216 |
|
217 | const handleMediaQueryChange = (matches) => {
|
218 | // matches will be true or false based on the value for the media query
|
219 | }
|
220 | const isDesktopOrLaptop = useMediaQuery(
|
221 | { minWidth: 1224 }, undefined, handleMediaQueryChange
|
222 | );
|
223 |
|
224 | return (
|
225 | <div>
|
226 | ...
|
227 | </div>
|
228 | )
|
229 | }
|
230 | ```
|
231 |
|
232 | ```jsx
|
233 | import React from 'react'
|
234 | import MediaQuery from 'react-responsive'
|
235 |
|
236 | const Example = () => {
|
237 |
|
238 | const handleMediaQueryChange = (matches) => {
|
239 | // matches will be true or false based on the value for the media query
|
240 | }
|
241 |
|
242 | return (
|
243 | <MediaQuery minWidth={1224} onChange={handleMediaQueryChange}>
|
244 | ...
|
245 | </MediaQuery>
|
246 | )
|
247 | }
|
248 | ```
|
249 |
|
250 | ## Easy Mode
|
251 |
|
252 | That's it! Now you can create your application specific breakpoints and reuse them easily. Here is an example:
|
253 |
|
254 | ```jsx
|
255 | import { useMediaQuery } from 'react-responsive'
|
256 |
|
257 | const Desktop = ({ children }) => {
|
258 | const isDesktop = useMediaQuery({ minWidth: 992 })
|
259 | return isDesktop ? children : null
|
260 | }
|
261 | const Tablet = ({ children }) => {
|
262 | const isTablet = useMediaQuery({ minWidth: 768, maxWidth: 991 })
|
263 | return isTablet ? children : null
|
264 | }
|
265 | const Mobile = ({ children }) => {
|
266 | const isMobile = useMediaQuery({ maxWidth: 767 })
|
267 | return isMobile ? children : null
|
268 | }
|
269 | const Default = ({ children }) => {
|
270 | const isNotMobile = useMediaQuery({ minWidth: 768 })
|
271 | return isNotMobile ? children : null
|
272 | }
|
273 |
|
274 | const Example = () => (
|
275 | <div>
|
276 | <Desktop>Desktop or laptop</Desktop>
|
277 | <Tablet>Tablet</Tablet>
|
278 | <Mobile>Mobile</Mobile>
|
279 | <Default>Not mobile (desktop or laptop or tablet)</Default>
|
280 | </div>
|
281 | )
|
282 |
|
283 | export default Example
|
284 | ```
|
285 |
|
286 | And if you want a combo (the DRY way):
|
287 |
|
288 | ```js
|
289 | import { useMediaQuery } from "react-responsive"
|
290 |
|
291 | const useDesktopMediaQuery = () =>
|
292 | useMediaQuery({ query: "(min-width: 1280px)" })
|
293 |
|
294 | const useTabletAndBelowMediaQuery = () =>
|
295 | useMediaQuery({ query: "(max-width: 1279px)" })
|
296 |
|
297 | const Desktop = ({ children }) => {
|
298 | const isDesktop = useDesktopMediaQuery()
|
299 |
|
300 | return isDesktop ? children : null
|
301 | }
|
302 |
|
303 | const TabletAndBelow = ({ children }) => {
|
304 | const isTabletAndBelow = useTabletAndBelowMediaQuery()
|
305 |
|
306 | return isTabletAndBelow ? children : null
|
307 | }
|
308 | ```
|
309 |
|
310 |
|
311 | ## Browser Support
|
312 |
|
313 | ### Out of the box
|
314 |
|
315 | <table>
|
316 | <tr>
|
317 | <td>Chrome</td>
|
318 | <td>9</td>
|
319 | </tr>
|
320 | <tr>
|
321 | <td>Firefox (Gecko)</td>
|
322 | <td>6</td>
|
323 | </tr>
|
324 | <tr>
|
325 | <td>MS Edge</td>
|
326 | <td>All</td>
|
327 | </tr>
|
328 | <tr>
|
329 | <td>Internet Explorer</td>
|
330 | <td>10</td>
|
331 | </tr>
|
332 | <tr>
|
333 | <td>Opera</td>
|
334 | <td>12.1</td>
|
335 | </tr>
|
336 | <tr>
|
337 | <td>Safari</td>
|
338 | <td>5.1</td>
|
339 | </tr>
|
340 | </table>
|
341 |
|
342 | ### With Polyfills
|
343 |
|
344 | Pretty much everything. Check out these polyfills:
|
345 |
|
346 | - [matchMedia.js by Paul Irish](https://github.com/paulirish/matchMedia.js/)
|
347 | - [media-match (faster, but larger and lacking some features)](https://github.com/weblinc/media-match)
|
348 |
|
349 | [downloads-image]: http://img.shields.io/npm/dm/react-responsive.svg
|
350 | [npm-url]: https://npmjs.org/package/react-responsive
|
351 | [npm-image]: http://img.shields.io/npm/v/react-responsive.svg
|