/react-responsive-starter

React project starter for composing responsive layouts

Primary LanguageJavaScript

Contributors Forks Stargazers Issues MIT License LinkedIn


react responsive starter example

React Responsive Application Starter

Easily set and capture the breakpoints that will work for your design.
Explore the docs »

View Demo · Bugs · Request Feature

Table of Contents

About The Project

React responsive starter grid example

Using the Window.MatchMedia method, the BreakPointState module can listen to screen and orientation changes passed in as props via a queries object. You will then have access to a custom useBreakpoint hook which is an explicit way of taking advantage of the context API anywhere down the component tree.

Built With

This project was bootstrapped with Create React App.

Getting Started

  1. Clone the react-responsive-starter
git clone https://github.com/adyngom/react-responsive-starter.git
  1. Install NPM packages
npm install && npm start

Usage

In your App.js file this would be your basic imports:

import React, { Fragment } from "react";
import { BreakpointState } from "./Breakpoint/BreakpointState";
import "./App.scss";

then you would specify a queries object with the different screen and orientation you may want to match:

const queries = {
  "for-phone-only": "(max-width: 559px)",
  "for-tablet-portrait-up": "(min-width: 600px)",
  "for-tablet-landscape-up": "(min-width: 900px)",
  "for-desktop-up": "(min-width: 1200px)",
  "for-big-desktop-up": "(min-width: 1800px)",
  portrait: "(orientation: portrait)",
  landscape: "(orientation: landscape)"
};

now you can use the BreakpointState as a wrapper around your app tree:

function App() {
  return (
    <Fragment>
      <BreakpointState queries={queries}>
        {/* Your App Components tree here */}
      </BreakpointState>
    </Fragment>
  );
}

Layout as a wrapper

With this initial setup, you can now have access to your queries matches inside any component using the context API with the convenient custom hook useBreakpoint. Let's look at an example where the Layout component is used a wrapper that provide global styles to the rest of the application.

/** Layout.js **/
import React from "react";
import { useBreakpoint } from "../Breakpoint/BreakpointState";

const Layout = ({ children, showBreakpoints }) => {
  const breakpoints = useBreakpoint();
  return (
    <div className={`wrapper ${breakpoints}`}>
      {!!showBreakpoints ? (
        <div className="meta">
          <small>Breakpoints: {breakpoints}</small>
        </div>
      ) : (
        ""
      )}
      {children}
    </div>
  );
};

export default Layout;

The two important lines are:

const breakpoints = useBreakpoint(); which gives a space separated set of your queries matches

<div className={wrapper ${breakpoints}}> where you attach those class names to your wrapper div.

Now you can import the Layout component and add it to your app:

/** App.js **/
import Layout from "./components/Layout";

function App() {
  return (
    <Fragment>
      <BreakpointState queries={queries}>
        <Layout showBreakpoints></Layout>
      </BreakpointState>
    </Fragment>
  );
}

you can see this behavior if you run your project and check the console.

Breakpoints reactive updates

The showBreakpoints is simply added for debugging and should not be part of your production code.

Now that you have access to those dynamic classes, you can either target them directly in your global styles within App.scss or you could put them within a component specific stylesheet. For this demo, we put them in the App.scss.

DUE TO THE NATURE OF CASCADING STYLES, THE ORDER OF THE CLASSES MATTERS SINCE ONE RESOLUTION MIGHT MATCH MULTIPLE CONDITIONS. STACK YOUR CLASSES FROM LOWEST BREAKPOINT TO HIGHEST

.wrapper {
  background-color: rgb(56, 17, 17);
  width: 100vw;
  min-height: 100vh;
  margin: 0;
  padding: 5vh 5vw;
  box-sizing: border-box;
  position: relative;

  .meta {
    position: absolute;
    top: 1em;
    text-align: center;
    width: 100%;
    font-size: 0.5em;
  }
  &.for-phone-only {
    background-color: #333;
  }
  &.for-tablet-portrait-up {
    background-color: rgb(94, 94, 185);
  }
  &.for-tablet-landscape-up {
    background-color: rgb(243, 40, 74);
  }
  &.for-desktop-up {
    min-height: 100vh;
    overflow: hidden;
    overflow-x: scroll;
    background-color: rgb(11, 161, 236);
    columns: 3 auto;
    header h1 {
      text-shadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9,
        0 5px 0 #aaa, 0 6px 1px rgba(0, 0, 0, 0.1), 0 0 5px rgba(0, 0, 0, 0.1), 0
          1px 3px rgba(0, 0, 0, 0.3), 0 3px 5px rgba(0, 0, 0, 0.2), 0 5px 10px
          rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.2), 0 20px 20px rgba(0, 0, 0, 0.15);
    }
  }
  &.for-big-desktop-up {
    background-color: rgb(243, 74, 40);
    header h1 {
      text-shadow: -10px 10px 0px #eaeeee, -20px 20px 0px #d2d6d6,
        -30px 30px 0px #787a7a;
    }
  }
}

We are having a bit of fun with some of the styles above, but essentially changing the background color of the wrapper container and using a column layout for big screens.

Let's add the Lipsum component to the mix to show how the content changes as we switch screen size.

function App() {
  return (
    <Fragment>
      <BreakpointState queries={queries}>
        <Layout>
          <Lipsum></Lipsum>
        </Layout>
      </BreakpointState>
    </Fragment>
  );
}
Cosmos awaits responsive example

Responsive Grid

The second example uses the PromoGrid component but we have attached a specific SCSS file to it PromoGrid.scss

/** PromoGrid.js **/
import React, { Fragment, useState } from "react";
import { useBreakpoint } from "../Breakpoint/BreakpointState";
import "./PromoGrid.scss";

const PromoGrid = () => {
  const breakpoints = useBreakpoint();
  const initialState = [
    // images object here
  ];

  const [gridImages, setGridImages] = useState(initialState);
  return (
    <Fragment>
      <div className={`promo-grid ${breakpoints}`}>
        {gridImages.map(Image => (
          <article
            key={Image.position}
            className={`fig-${Image.position}`}
            style={{
              background: `url(${Image.url})`,
              backgroundSize: "cover"
            }}
          ></article>
        ))}
      </div>
    </Fragment>
  );
};

export default PromoGrid;

The setup to get the breakpoints is similar to what we have done with Layout.js earlier and essentially allow us to get the responsive classes added on this line

<div className={promo-grid ${breakpoints}}>

Now the CSS to make the grid responsive is a little bit more involved, but essentially following a mobile-first approach, start with the generic rules as default styles:

.promo-grid {
  display: grid;
  max-width: 1170px;
  padding: 10px;
  height: auto;
  grid-template-columns: repeat(1, 1fr);
  grid-auto-rows: minmax(190px, 1fr);
  gap: 10px;
  // ... rest of rules
}

and we define our first layout changes in our tablet display for example:

.for-tablet-portrait-up {
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(7, 238px);
  .fig-1 {
    grid-column: 1 / 2;
    grid-row: 1 / 2;
  }
  .fig-4 {
    grid-column: 2 / 3;
    grid-row: 2 / 4;
  }
  .fig-5 {
    grid-row: 3 / 5;
  }
  .fig-8 {
    grid-column: 1 / 2;
    grid-row: 5 / 7;
  }
}

Now in App.js after importing the PromoGrid we can try:

function App() {
  return (
    <Fragment>
      <BreakpointState queries={queries}>
        <PromoGrid></PromoGrid>
      </BreakpointState>
    </Fragment>
  );
}

Click on this link to see the effect

That's all folks :)

Please add any suggestions or better yet refine it by contributing to the project. Hope you find it useful.

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Your Name - @adyngom - email

Project Link: https://github.com/adyngom/react-responsive-starter

Acknowledgements