Learn about our RFC process, Open RFC meetings & more.Join in the discussion! ¬Ľ

react-only

2.3.3¬†‚Äʬ†Public¬†‚Äʬ†Published

react-only

npm version downloads js-standard-style

gzipped size stability speed

react-only is inspired by the .visible classes from bootstrap 4 (or .hidden classes from bootstrap 3): only display a certain content for a precise screen size.

It allows you to display component only for particular screen sizes.

If you need a responsive layout and adaptive components, react-only is here for you!

See changelog

How to use

  1. <Only>
    1. Default breakpoints
    2. Additional Up and Down
    3. Match Media Queries
    4. Render as component
    5. Strict mode
  2. Hooks
    1. useOnly()
    2. useQuery()
  3. <Match>
    1. only and matchMedia props
    2. Use a custom component in Match
    3. TypeScript support
  4. <BreakpointsProvider>
    1. Add more breakpoints
    2. Change default breakpoints
    3. Units
  5. CSS in JS
    1. toJSON
    2. toCSS
  6. Comparison to other libraries
  7. matchMedia polyfill
  8. FAQ

<Only>

Default breakpoints

react-only is based on the classic bootstrap breakpoints: xs, sm, md, lg and xl.

import React from "react";
import { Only } from "react-only";
 
const App = () => (
  <React.Fragment>
    <Only on="xs">Only visible for extra small devices (portrait phones)</Only>
    <Only on="sm">Only visible for small devices (landscape phones)</Only>
    <Only on="md">Only visible for medium devices (tablets)</Only>
    <Only on="lg">Only visible for large devices (desktops)</Only>
    <Only on="xl">Only visible for extra large devices (large desktops)</Only>
    <Only on="sm xl">Only visible for small AND extra large devices</Only>
  </React.Fragment>
);

By default, the breakpoints are:

Breakpoint From To
xs 0px 575px
sm 576px 767px
md 768px 991px
lg 992px 1199px
xl 1200px Infinity

Additional Up and Down

In addition to the regular breakpoints, you have another api defined {breakpoint}Up and {breakpoint}Down:

import React from "react";
import { Only } from "react-only";
 
const App = () => (
  <React.Fragment>
    <Only on="smUp">Visible on every device bigger or equal than "small"</Only>
    <Only on="mdDown">Visible on every device smaller or equal than "medium"</Only>
  </React.Fragment>
);

Match Media Queries

For more advanced media queries, the prop matchMedia can be set to any regular query supported by window.matchMedia.

import React from "react";
import { Only } from "react-only";
 
const App = () => (
  <Only matchMedia="(min-device-width: 500px) and (orientation: landscape)">
    Visible on every device bigger than "500px" and in landscape mode
  </Only>
);

More infos about CSS media queries

Note: If you use breakpoints AND matchMedia, the component will be displayed if one of the breakpoints is matched OR if the media query is fulfilled.

Render as component

If you want the Only components to render as another component, you can use the as props:

import React from "react";
import { Only } from "react-only";
 
const App = () => (
  <ul>
    <Only as="li" on="xs">
      Only visible for extra small devices (portrait phones)
    </Only>
    <Only as="li" on="sm">
      Only visible for small devices (landscape phones)
    </Only>
    <Only as="li" on="md">
      Only visible for medium devices (tablets)
    </Only>
    <Only as="li" on="lg">
      Only visible for large devices (desktops)
    </Only>
    <Only as="li" on="xl">
      Only visible for extra large devices (large desktops)
    </Only>
    <Only as="li" on="sm xl">
      Only visible for small AND extra large devices
    </Only>
  </ul>
);

The as props can take any DOM tag string (div, ul, li, ...) or any React component:

import React from "react";
import { Only } from "react-only";
 
const Custom = ({ title, children }) => (
  <React.Fragment>
    <h3>{title}</h3>
    <p>{children}</p>
  </React.Fragment>
);
 
const App = () => (
  <React.Fragment>
    <Only as={Custom} title="xs" on="xs">
      Only visible for extra small devices (portrait phones)
    </Only>
    <Only as={Custom} title="sm" on="sm">
      Only visible for small devices (landscape phones)
    </Only>
    <Only as={Custom} title="md" on="md">
      Only visible for medium devices (tablets)
    </Only>
    <Only as={Custom} title="lg" on="lg">
      Only visible for large devices (desktops)
    </Only>
    <Only as={Custom} title="xl" on="xl">
      Only visible for extra large devices (large desktops)
    </Only>
    <Only as={Custom} title="sm xl" on="sm xl">
      Only visible for small AND extra large devices
    </Only>
  </React.Fragment>
);

Note that any props except for matchMedia, as and on will be forwarded to the as props.

Strict mode

When strict is set in the props, the margins are offset by 1 px:

import React from "react";
import { Only } from "react-only";
 
const App = () => (
  <React.Fragment>
    <Only on="xs">Only visible for range: [576px, 768px]</Only>
    <Only on="xs" strict>
      Only visible for range: [577px, 767px]
    </Only>
  </React.Fragment>
);

Hooks

useOnly()

useOnly is a hook that detects if the given breakpoint matches the current viewport.

import React from "react";
import { useOnly } from "react-only";
 
const App = () => {
  const matchXl = useOnly("xl");
  const matchMdDown = useOnly("mdDown");
  const matchMdStrict = useOnly("md", true);
  return (
    <ul>
      {matchXl && <li>Visible on every "large" device</li>}
      {matchMdDown && <li>Visible on every device smaller or equal than "medium"</li>}
      {matchMdStrict && <li>Visible on every strict "medium" device</li>}
    </ul>
  );
};

useQuery()

useQuery is a hook that detects if the given media query matches the current viewport.

import React from "react";
import { useQuery } from "react-only";
 
const App = () => {
  const matchMediaQuery = useQuery("(min-width:768px) and (max-width:992px),(max-width:576px)");
  return <ul>{matchMediaQuery && <li>Visible at (min-width:768px) and (max-width:992px),(max-width:576px)</li>}</ul>;
};

<Match>

only and matchMedia props

The Match will look into every props of its children (and event nested children) to detect only, matchMedia and strict props. If one of those is found, it will wrap this component inside a Only component will match only with on and matchMedia and strict to theirself.

import React from "react";
import { Only, Match } from "react-only";
 
const App = () => (
  <Match>
    <div only="xs">xs</div>
    <div only="sm">sm</div>
    <div only="md">md</div>
    <div only="lg" strict>
      strict lg
    </div>
    <div only="xl">xl</div>
    <div>
      <div>
        <div>
          <div only="smDown">nested smDown</div>
        </div>
      </div>
    </div>
    <div matchMedia="(min-width:768px) and (max-width:992px),(max-width:576px)">
      {"(min-width:768px) and (max-width:992px),(max-width:576px)"}
    </div>
  </Match>
);

Use a custom component in Match

You can also render the Match component as another one:

import React from "react";
import { Only, Match } from "react-only";
 
const App = () => (
  <Match as="ul">
    <li only="xs">xs</li>
    <li only="sm">sm</li>
    <li only="md">md</li>
    <li only="lg">lg</li>
    <li only="xl">xl</li>
  </Match>
);

TypeScript support

This library is fully written in TypeScript.

‚ö†ÔłŹ But there is currently no full TypeScript support for the Match component when it is used with DOM elements. For now you can only use Match with custom components as children:

import * as React from "react";
import { Match, MatchChildProps } from "react-only";
 
// MatchChildProps includes the props `only` and `matchMedia`
interface CustomProps extends MatchChildProps {
  title: string;
}
 
const Custom: React.FunctionComponent<CustomProps> = ({ title, children }) => (
  <React.Fragment>
    <h3>{title}</h3>
    <p>{children}</p>
  </React.Fragment>
);
 
const App = () => (
  <Match>
    <Custom only="xs" title="xs">
      xs
    </Custom>
    <Custom only="sm" title="sm">
      sm
    </Custom>
    <Custom only="md" title="md">
      md
    </Custom>
    <Custom only="lg" title="lg">
      lg
    </Custom>
    <Custom only="xl" title="xl">
      xl
    </Custom>
  </Match>
);

<BreakpointsProvider>

BreakpointsProvider defines the values of every breakpoints.

Use it to inject or modify the breakpoints (only use one BreakpointsProvider per build).

Add more breakpoints

import React from "react";
import { Only, BreakpointsProvider } from "react-only";
 
const App = () => (
  <BreakpointsProvider additionalBreakpoints={{ customBrkPts: [263, 863] }}>
    <Only on="customBrkPts">Visible on every device from "263px" to "863px"</Only>
    <Only on="customBrkPtsUp">Visible on every device bigger than "263px"</Only>
    <Only on="customBrkPtsDown">Visible on every device smaller than "863px"</Only>
  </BreakpointsProvider>
);

Change default breakpoints

import React from "react";
import { Only, BreakpointsProvider } from "react-only";
 
const App = () => (
  <BreakpointsProvider breakpoints={{ sm: [263, 863] }}>
    <Only on="sm">Visible on every device from "263px" to "863px"</Only>
    <Only on="smUp">Visible on every device bigger than "263px"</Only>
    <Only on="smDown">Visible on every device smaller than "863px"</Only>
  </BreakpointsProvider>
);

Warning: This overrides completely the default breakpoints, in this example, the other breakpoints xs, md, lg and xl are no longer defined!

Units

You can specify which unit is going to be used for the breakpoint by specifying in the 3rd option a "unit" key.

By default, the unit is "px".

import React from "react";
import { Only, BreakpointsProvider } from "react-only";
 
const App = () => (
  <BreakpointsProvider
    additionalBreakpoints={{
      pxPoint: [263, 863, { unit: "px" }],
      emPoint: [20, 40, { unit: "em" }],
    }}
  >
    <Only on="pxPoint">Visible on every device from "263px" to "863px"</Only>
    <Only on="emPoint">Visible on every device from "20em" to "40em"</Only>
  </BreakpointsProvider>
);

Direction

You can specify which direction is used for the media queries (height or width).

By default, "width" is the chosen direction.

import React from "react";
import { Only, BreakpointsProvider } from "react-only";
 
const App = () => (
  <BreakpointsProvider
    breakpoints={{
      xBreakpoint: [300, 500, { direction: "width" }],
      yBreakpoint: [200, 400, { direction: "height" }],
    }}
  >
    <Only on="xBreakpoint">Visible on every device from "300px" to "500px" wide</Only>
    <Only on="yBreakpoint">Visible on every device from "200px" to "400px" tall</Only>
  </BreakpointsProvider>
);

Every CSS units are supported.

The default unit is px.

CSS in JS

react-only includes 2 utility functions toJSON and toCSS so that you can re-use react-only breakpoints as media queries for css-in-js libraries.

toJSON

Example with styletron:

import React from "react";
import { toJSON as createToJSON, BreakpointsContext } from "react-only";
import { styled } from "styletron-react";
 
const styles = {
  mdDown: {
    color: "red",
    ":hover": { color: "blue" },
  },
  lgUp: {
    color: "green",
  },
};
 
const Panel = styled("div", (props) => ({
  ...props.$toJSON(styles),
}));
 
const App = () => {
  const breakpoints = React.useContext(BreakpointsContext);
  const toJSON = createToJSON(breakpoints);
  // toJSON(styles) returns:
  // {
  //   "@media  (max-width:991px)": {
  //     "color": "red",
  //     ":hover": {
  //       "color": "blue"
  //     }
  //   },
  //   "@media  (min-width:992px)": {
  //     "color": "green"
  //   }
  // }
  return <Panel $toJSON={toJSON}>content</Panel>;
};

toCSS

Example with emotion:

import React from "react";
import { toCSS as createToCSS, BreakpointsContext } from "react-only";
import { css } from "emotion";
 
const styles = {
  mdDown: {
    color: "red",
    ":hover": { color: "blue" },
  },
  lgUp: {
    color: "green",
  },
};
 
const App = () => {
  const breakpoints = React.useContext(BreakpointsContext);
  const toCSS = createToCSS(breakpoints);
  // toCSS(styles) returns:
  // `@media  (max-width:991px) {
  //   color: red;
  //   :hover {
  //     color: blue;
  //   }
  // }
  // @media  (min-width:992px) {
  //   color: green;
  // }`
  return <div className={css(toCSS(styles))}>content</div>;
};

Comparison to other libraries

Lib Breakpoints Custom breakpoints Media query matchMedia listener' hooks SSR support
react-only ‚úÖ ‚úÖ ‚úÖ ‚úÖ ‚úÖ ‚úÖ
react-responsive ‚ĚĆ ‚ĚĆ ‚úÖ ‚úÖ ‚úÖ ‚úÖ
react-breakpoints ‚úÖ ‚úÖ ‚ĚĆ ‚ĚĆ ‚ĚĆ ‚úÖ
react-responsive-breakpoints ‚úÖ ‚ĚĆ ‚ĚĆ ‚ĚĆ ‚ĚĆ ‚ĚĆ

': matchMedia listener event means that the library is built around matchMedia.addListener(callback) and not window.addEventListener('resize', callback) (which is faster because the callback is only triggered when the media query's state changes and not at every resize).

matchMedia polyfill

Browser

If you are on want to use matchMedia on browser that don’t support it, I’d recommend you to use matchmedia-polyfill.

Node

If you want to mock matchMedia on Node to execute tests for instance, you can use mock-match-media.

And if you need an example with Jest, @testing-library/react, React and react-only, you can take a look at these tests.

FAQ

For other questions, please take a look at our FAQ document.

Install

npm i react-only

DownloadsWeekly Downloads

20

Version

2.3.3

License

MIT

Unpacked Size

77.4 kB

Total Files

21

Last publish

Collaborators

  • avatar