This API is largely based on styled-system's responsive styles, it is not exactly the same however. Their documentation has a lot of great examples of behavior, however please refer to our documentation for our own best practices!
Creating components that handle many screensizes can be tricky. Often we need to change specific CSS properties at different breakpoints to ensure that a component does not render in a way that will break the page or make it unusable. This leads to a problem for maintainers and reviewers:
Traditional (S)CSS strategies have approached this in various ways:
We've taken these two core values to heart by adopting a responsive property syntax that ensures that:
Here is an example:
<Box display={{ _: 'none', sm: 'block' }} />
Output styles:
.Box {display: 'none';@media (min-width: 480px) {display: 'block';}}
We've matched this syntax to each of our named breakpoints:
This syntax is declarative and unstructured e.g. padding={{ xl: 64 }}
export interface MediaQueryMap<T> {_?: T; // No media queryxs?: T; // `xs` media querysm?: T; // `sm` media querymd?: T; // `md` media querylg?: T; // `lg` media queryxl?: T; // `xl` media query}
This structure is implicit but ordered e.g. padding={[16, 24, 32, 48]}
export interface MediaQueryArray<T> {0?: T; // No media query1?: T; // `xs` media query2?: T; // `sm` media query3?: T; // `md` media query4?: T; // `lg` media query5?: T; // `xl` media query}
Both are valid syntaxes for all stystem props:
export type ResponsiveProp<T> = T | MediaQueryMap<T> | MediaQueryArray<T>;
Here are some examples of what the expected output will be for certain configurations:
// 1<Box p={[16, 24]} py={12} />// 2<Box width={{ _: '100%', xl: '50%' }} />// 3<Box display={{ lg: 'none' }} />
/** 1 */.Box {padding: 12px 16px;@media (min-width: 480px) {padding: 12px 24px;}}/** 2 */.Box {width: 100%;@media (min-width: 1440px) {width: 50%;}}/** 3 */.Box {@media (min-width: 1200px) {display: none;}}
Since both syntaxes perform the same task it can be unclear which syntax is preferrable to another, heres some best practices for picking the syntax that will be most readable.
// Simple<Text fontSize={{ lg: 26 }} />// Unreadable because there are no values for everything preceding `lg`<Text fontSize={[ , , , 26]} />
// 14 at the smallest size and 64 at the largest<Text fontSize={{ _: 14, xl: 64 }} />// Counting commas will put you to sleep faster than sheep<Text fontSize={[14, , , ,64]} />
// Order and readable<Text fontSize={[14, 16, 18, 20, 26, 64]} />// Unordered and verbose<TextfontSize={{md: 20,_:14,xs: 16,xl: 64,sm: 18,lg: 26}}/>
// looks safe but will render as 1 column at smallest screen size<Column size={{ xs: 12, sm: 6 }} />// this will not as we must explicity declare the breakpoint value as undefined<Column size={[12, ,6]} />