Responsive System
React Visage has a responsive system that works with the screen classes and breakpoints defined by Visage, so that you can make your components adjust responsively based on those sizes and breakpoints.
It configures and exports a Responsive System generated by react-responsive-system.
(This system is only available via React. For the vanilla API, you can use our design tokens in your stylesheets to adjust your CSS based on the screen size.)
Usage
Render the ScreenClassProvider
at the root of your app.
// index.tsximport { ScreenClassProvider } from '@vp/visage'function Root() {return (<ScreenClassProvider><App /></ScreenClassProvider>)}
useScreenClass
You can useScreenClass
in your components to find out the current screen size: "xs", "sm", "md", or "lg".
// some-component.tsximport { useScreenClass, Carousel } from '@vp/visage'const propsByScreenClass = {xs: { slidesToShow: 1 },sm: { slidesToShow: 2 },md: { slidesToShow: 3 },lg: { slidesToShow: 3 },}function SomeComponent() {const screenClass = useScreenClass()console.log(screenClass) // "xs" or "sm" or "md" or "lg"return <Carousel {...propsByScreenClass[screenClass]} />}
useIsScreenClassInitialized
It returns a boolean value and tells if the ScreenClassProvider is initialized on the browser or not.
By default, the useScreenClass
hook returns the value "xs" until the ScreenClassProvider is initialized on the browser, and useIsScreenClassInitialized
hook can be useful in this case if you are interested in the actual on-screen render value rather than the default value.
// some-component.tsximport { useIsScreenClassInitialized, Carousel } from '@vp/visage'function SomeComponent() {const isScreenClassInitialized = useIsScreenClassInitialized()console.log(isScreenClassInitialized) // initially false and then true after initializationreturn <Carousel someProps />}
responsive
You can also use the responsive
function in order to make your component responsive.
// some-component.tsximport { responsive, Carousel } from '@vp/visage'const ResponsiveCarousel = responsive(Carousel)function SomeComponent() {return (<ResponsiveCarouselxs={{ slidesToShow: 1 }}sm={{ slidesToShow: 2 }}md={{ slidesToShow: 3 }}lg={{ slidesToShow: 3 }}/>)}
responsive
components are based on the mobile-first pattern which means that any overrides will affect larger screen sizes as well as their own screen size. In our example, md
and lg
screens both need to have slidesToShow = 3
. We can simply omit the lg
override here and our responsive
Carousel will inherit the md
overrides!
// some-component.tsximport { responsive, Carousel } from '@vp/visage'const ResponsiveCarousel = responsive(Carousel)function SomeComponent() {return (<ResponsiveCarouselxs={{ slidesToShow: 1 }} // affects xs _and larger_sm={{ slidesToShow: 2 }} // affects sm _and larger_md={{ slidesToShow: 3 }} // affects md _and larger_/>)}
Finally, since our responsive
component is mobile-first we don't need to specify an override for xs
. xs
is the default configuration for the component, so we can write it like this:
// some-component.tsximport { responsive, Carousel } from '@vp/visage'const ResponsiveCarousel = responsive(Carousel)function SomeComponent() {return (<ResponsiveCarouselslidesToShow={1}sm={{ slidesToShow: 2 }} // affects sm _and larger_md={{ slidesToShow: 3 }} // affects md _and larger_/>)}
Adding custom screen classes
If you need to support custom screen classes, you can easily create a custom Responsive System! This is the entire source-code for our Responsive System implementation:
import { createResponsiveSystem } from 'react-responsive-system'import { screenClassMaxWidths } from '@vp/visage'export const {ScreenClassProvider,useScreenClass,responsive,useResponsiveProps,} = createResponsiveSystem({breakpoints: screenClassMaxWidths,defaultScreenClass: 'xs',cascadeMode: 'mobile-first',})
Simply create a new file and name it something like responsive-system.ts
and use the above implementation for reference.
Per the react-responsive-system
docs, the breakpoints
object is a map from screen class name to the maximum pixel-width for that screen class.
Visage's breakpoints
object comes directly from the @vp/visage
package and it looks like this:
const customScreenSizes = {xs: 767, // xs = 0 - 767sm: 1023, // sm = 768 - 1023md: 1439, // md = 1024 - 1439lg: Infinity, // lg = 1440 - Infinity}
Also from the react-responsive-system
docs:
Exactly one breakpoint must have a value of
Infinity
Now we have all of the info required in order to customize our own Responsive System! Let's say that we want a breakpoint that's smaller than xs
and we want to have another breakpoint that's larger than lg
.
Our new breakpoints
object should look like this:
const customScreenSizes = {xxs: 320, // xxs = 0 - 320xs: 767, // xs = 321 - 767sm: 1023, // sm = 768 - 1023md: 1439, // md = 1024 - 1439lg: 1600, // lg = 1440 - 1600xl: Infinity, // xl - 1601 - Infinity}
Note that we made three changes:
We added
xxs = 320
We changed
lg
fromInfinity
to1600
We added
xl = Infinity
Here's how you could do that in code:
import { createResponsiveSystem } from 'react-responsive-system'import { screenClassMaxWidths } from '@vp/visage'const myCustomBreakpoints = {...screenClassMaxWidths,xxs: 320,lg: 1600,xl: Infinity,}export const {ScreenClassProvider,useScreenClass,responsive,useResponsiveProps,} = createResponsiveSystem({breakpoints: myCustomBreakpoints,defaultScreenClass: 'xs',cascadeMode: 'mobile-first',})