Responsive props for Styled Components.
responsive-props
is a HOC that enhances a styled component with a responsive API, to handle styling based on any number of media queries.
This is useful when a styled component needs to have different styles based on one or more media queries, in different contexts of an application.
A common example of this is a column in a grid, where a column can have a different widths depending on a matching media query. For this particular use case, responsive-props
can provide the following API:
// Possibility to target specific media queries and apply styles accordingly
<Row>
<Column span={{ m: 6, l: 4, xl: 3 }} />
</Row>
// Or pass a single value that will apply styles without any media queries
<Row>
<Column span={6} />
</Row>
The above example is take from the Styled Flexbox Grid library, which uses responsive-props
.
yarn add responsive-props
# or
npm install responsive-props
The default export of responsive-props
is a HOC that takes two parameters. The first parameter is the component to be wrapped/enhanced, and the second parameter is an object containing functions/mixins, that will generate styles for a given media query.
import React from "react";
import styled, { css } from "styled-components";
// responsive-props HOC
import withResponsiveProps from "responsive-props";
// Create a styled-components
const StyledComponent = styled.div`
width: 200px;
height: 200px;
background: palevioletred;
// Styles returned from mixins targeting specific media queries will be added here
${({ responsiveProps }) => responsiveProps}
`;
// Define the mixin `background`
const background = bg => css`
background: ${bg};
`;
// Wrap `StyledComponent with the `responsive-props` HOC
const WrappedStyledComponent = withResponsiveProps(
// Wraps `StyledComponent
StyledComponent,
{
// registers ´background` as a mixin
background: background
}
);
// Define the breakpoints, passed to `WrappedStyledComponent` `breakpoints` prop bellow
const breakpoints = { xs: 320, s: 576, m: 768, l: 992, xl: 1200 };
// WrappedStyledComponent can now be used in the following way
const Example = () => (
<WrappedStyledComponent
background={{ s: "#002635", m: "#013440", l: "#AB1A25" }}
breakpoints={breakpoints}
/>
);
export default Example;
The above component WrappedStyledComponent
, will result in a div in the shaped of a square, with different background colors depending on what media query is matching.
Notice how different breakpoint are targeted inside of the background
prop of WrappedStyledComponent
. The value for each breakpoint (#002635
, #013430
and #AB1A25
) will be passed as the bg
parameter of the background
mixin, and generate corresponding styled for each media query.
<WrappedStyledComponent
background={{ s: "#002635", m: "#013440", l: "#AB1A25" }}
breakpoints={breakpoints}
/>
Also notice that the name of the prop background
, matches that of the key background
in the object of mixins that is passed to the withResponsiveProps
HOC.
const WrappedStyledComponent = withResponsiveProps(
// Wraps `StyledComponent
StyledComponent,
{
// registers ´background` as a mixin
background: background
}
);
Important: The line
${({ responsiveProps }) => responsiveProps}
is where styles of each media queries will be inserted. Without this no media queries will be applied to the styled component.
It is possible to register any number of breakpoints with a naming convention of your choice. In the above examples we used the naming convention: xs
, s
, m
, l
, xl
. However if you for example prefer the convention used by Twitter Bootstrap (xs
, sm
, md
, lg
, xl
) you could configure the breakpoints like this:
// Define the breakpoints, passed to `WrappedStyledComponent` `breakpoints` prop bellow
const breakpoints = { xs: 320, sm: 576, md: 768, lg: 992, xl: 1200 };
// WrappedStyledComponent can now be used in the following way
const Example = () => (
<WrappedStyledComponent
background={{ sm: "papayawhip", md: "palevioletred", lg: "#AB1A25" }}
breakpoints={breakpoints}
/>
);
There are two ways to register the breakpoints for components enhanced by responsive-props
.
The first (which has already been demonstrated in the Basic Example is to pass to pass an object of breakpoints to the enhanced component via the breakpoints
prop. The other more convenient way is to register the breakpoints inside a theme of the styled-components
ThemeProvider.
Putting the breakpoints inside a theme has the benefit of only having to define them once, and not having to remember to include for every component.
The breakpoints should be put under the namespace responsiveProps.breakpoints
of the theme, as demonstrated bellow.
import React from 'react';
import { ThemeProvider } from 'styled-components';
const theme = {
responsiveProps: {
breakpoints: {
xs: 320,
s: 576,
m: 768,
l: 992,
xl: 1200
}
}
}
// The `breakpoints` prop from the `Basic Example` can now be omitted
const Example = () => (
<ThemeProvider theme={theme}>
<WrappedStyledComponent background={{ s: '#002635', m: '#013440', l: '#AB1A25' }} />
<ThemeProvider theme={theme}>
);
Of course this is a contrived example where the benefit of theme isn't very clear. Normally the ThemeProvider
would be placed somewhere higher up the component three, where any component inside the ThemeProvider
can omit the breakpoints
prop.
If your application doesn't make use of ThemeProvider
(or you would like to override the default breakpoints provided by theme) it is possible to pass breakpoints via the breakpoints
prop, of a component enhanced by responsive-props
.
<WrappedStyledComponent breakpoint={{ xs: 320,s: 576,m: 768,l: 992, xl: 1200 }} >
The API of a component enhanced by responsive-props
is centered around the format of the value, that is passed to the props of the component. They can either be in the form of an object to target specific media queries or a single value to seamlessly act as regular adaptational props.
In React terms the pattern implemented by responsive-props
is known as Props Proxy.
To target a specific breakpoint an object of breakpoints is passed as the value of the prop. The keys of the of object should be present in the registered breakpoints in order to work.
Bellow the keys (s
, m
, and l
) are the breakpoints to target. The values (#002635
, #013440
and #AB1A25
) are parameter that will be passed to a mixin/function namned background
, responsible for generating styles for the specified breakpoints.
<WrappedStyledComponent
background={{ s: "#002635", m: "#013440", l: "#AB1A25" }}
/>
This will result in different background colors (#002635
, #013440
and #AB1A25
) for each breakpoint (s
, m
, and l
).
If a style should be applied without media queries (i.e. independent of the bowser/viewport width) it is possible to only pass a single value to the same prop, instead of an object of breakpoints.
<WrappedStyledComponent background="#002635" />
This will result in a background color of #002635
for all viewports.
If a mixin accept more than one parameter it is possible to pass the parameter for a given breakpoint in the form on an array. In the example bellow the verticalPadding
mixin takes two parameters, the first for top padding and the second for bottom padding.
<WrappedStyledComponent verticalPadding={{ s: ['2rem', '1rem'], m: ['3rem', '2rem'] }}
More detailed snippet of the above example:
// Define the mixin `background`
const verticalPadding = (paddingBottom, paddingTop = 0) => css`
padding: ${paddingTop} 0 ${paddingBottom} 0;
`;
// Wrap `StyledComponent with the `responsive-props` HOC
const WrappedStyledComponent = withResponsiveProps(
// Wraps `StyledComponent`
StyledComponent,
{
// registers `verticalPadding` as a mixin
verticalPadding: verticalPadding
}
);
// WrappedStyledComponent can now be used in the following way
const Example = () => (
<WrappedStyledComponent
verticalPadding={{ s: ["2rem", "1rem"], m: ["3rem", "2rem"] }}
/>
);
innerRef
and nodeRef
is deprecated as of responsive-props
v2. Instead V2 implements the new React.forwardRef
API and expects the use of ref
prop to get the underlaying DOM element.
responsive-props
v2 is compatible with styled-components: ^4.0.0
and react ^16.3.0
. Make sure to match these dependencies or consider using an older version.
If you wish to use styled-components
v3 use version 1.2.1
of responsive-props
. Note that if you're using later versions of React
this may throw warnings, updating is recommended.