Easily set and capture the breakpoints that will work for your design.
Explore the docs »
View Demo
·
Bugs
·
Request Feature
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.
This project was bootstrapped with Create React App.
- Clone the react-responsive-starter
git clone https://github.com/adyngom/react-responsive-starter.git
- Install NPM packages
npm install && npm start
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>
);
}
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.
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
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
Please add any suggestions or better yet refine it by contributing to the project. Hope you find it useful.
See the open issues for a list of proposed features (and known issues).
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.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the MIT License. See LICENSE
for more information.
Your Name - @adyngom - email
Project Link: https://github.com/adyngom/react-responsive-starter
- Super thanks to @Udit Tyagi with this article that inspired everything
- A must read article by David Gilbertson - The 100% correct way to do CSS breakpoints that impacted the default set of breakpoints names in the examples. You can of course name them whatever you see fit but read his article first.
- Thanks to Design Shack for this very entertaining piece 12 Fun CSS Text Shadows You Can Copy and Paste
- Best Readme Template for a superb documentation starter
- Last but not least Sagan Ipsum for a different take on sample text.