DEV Community

loading...

@blocz/react-responsive v3 is out

Ayc0
I try to build good tools for JavaScript and React πŸ˜…
・3 min read

The v3 of @blocz/react-responsive was just released with few bug fixes and new names. You can check out the full release details here: https://github.com/bloczjs/react-responsive/releases/tag/v3.0.0

Features

  • performance
  • TypeScript support
  • CSS-in-JS compatibilities
  • customizable
  • SSR compatible

Some history

3 years ago, I needed a way in react to display a component or another one, depending on whether or not the page was viewed on mobile or in desktop. I had 2 things in mind:

  • avoid rendering some components depending on the viewport size (and not using display: null),
  • define a set of predefined breakpoints and not having to redefine them every time,
  • breakpoints should be ranges of sizes instead of actual breakpoints: when someone uses md, they usually don't want to apply this to sm too (except if you specify md down).

And none of the libraries that existed at the time were able to provide those features. So I created mine: react-only.

This library evolved as the react community evolved too:

v3

All this time, we kept the name react-only but it never described what this library was for. So in this v3, we decided to rename it to @blocz/react-responsive and in general to use better names for the exported functions.

API

Hooks

@blocz/react-responsive is centered around 2 hooks:

  • useMediaQuery to detect if the current view matches the given media query (string)
  • useBreakpoint to detect if the current view matches predefined breakpoints

Example:

import { useBreakpoint, useMediaQuery } from "@blocz/react-responsive";

const Breakpoints = () => {
  const matchXl = useBreakpoint("xl");
  const matchMdDown = useBreakpoint("mdDown");
  const matchMdOrLg = useBreakpoint("md lg");
  return (
    <ul>
      {matchXl && <li>Visible on every "large" device</li>}
      {matchMdDown && <li>Visible on every device smaller or equal than "medium"</li>}
      {matchMdOrLg && <li>Visible on every "medium" or "large" device</li>}
    </ul>
  );
};

const MediaQuery = () => {
  const matchMediaQuery = useMediaQuery("(min-width:768px) and (max-width:992px)");
  return <ul>{matchMediaQuery && <li>Visible at (min-width:768px) and (max-width:992px)</li>}</ul>;
};
Enter fullscreen mode Exit fullscreen mode

Performance

To check if a breakpoint / media query matches or not the current viewport, we don't use event listeners on the resize event, but instead we use matchMedia so that we only run JS code when the media queries start/stop matching and not at each resize.

Breakpoints

By default, those predefined breakpoints are used:

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

And also all those breakpoints exist in Up and Down variants: smDown is from 0px to 767px, etc.

But if you need other breakpoints, you can use the <BreakpointProvider> component

Direction

Breakpoints are by default set on the horizontal axis, but you can also set them on the vertical axis to check the height of the viewport.

Unit

By default, breakpoint will use px but you can use em or any valid CSS unit.

CSS-in-JS

When we created the library, we were using styletron for our styles, and we wanted to bind the breakpoints we defined in @blocz/react-responsive with the breakpoints used for our styles.

So we added support for CSS-in-JS with our toJSON (for a library like styletron) and toCSS (for a library like emotion) utility functions:

import React from "react";
import { toJSON as createToJSON, toCSS as createToCSS , BreakpointsContext } from "@blocz/react-responsive";

const styles = {
  mdDown: {
    color: "red",
    ":hover": { color: "blue" },
  },
  lgUp: {
    color: "green",
  },
};

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"
  //   }
  // }

  const toCSS = createToCSS(breakpoints);
  // toCSS(styles) returns:
  // `@media  (max-width:991px) {
  //   color: red;
  //   :hover {
  //     color: blue;
  //   }
  // }
  // @media  (min-width:992px) {
  //   color: green;
  // }`
Enter fullscreen mode Exit fullscreen mode

SSR

The library by itself doesn’t provide any mocks for window.matchMedia for SSR. But if you use one, like mock-match-media, @blocz/react-responsive will listen to it.

If you need an example, you can check out the tests done here: https://github.com/bloczjs/react-responsive/blob/master/packages/tests/src/__tests__/ssr.ts

We render a page with @testing-library/react's render function on multiple different screen sizes with mock-match-media's setMedia function.

Discussion (1)

Collapse
prince272 profile image
Prince Owusu

@blocz/react-responsive