Efficient component creation with styled system
Our team uses styled-components to style react components .
There are already articles on styled-components on Habré, therefore we will not dwell on this in detail.
Introducing Styled components
Better, faster, more powerful: styled-components v4
Having written many components, we found that in almost every component we copy duplicate properties.
For example, in many components we wrote like this:
padding-top: ${props => props.paddingTop || '0'};
padding-bottom: ${props => props.paddingBottom || '0'};
padding-right: ${props => props.paddingRight || '0'};
padding-left: ${props => props.paddingLeft || '0'};
Styled system
Copying duplicate properties started to get annoying, and we pulled duplicate pieces of code into separate reusable functions. But I thought that maybe someone had already implemented something like this before us and probably more beautifully and universally. I started to google and found a styled system .
Styled-System provides a set of style features. Each style function provides its own set of properties that style elements based on the values defined in the application theme. The styled system has a rich API with functions for most CSS properties.
Styled system example based on styled-components
import { space, width, fontSize, color } from 'styled-system';
import styled, { ThemeProvider } from 'styled-components';
import theme from './theme';
const Box = styled.div`
${space}
${width}
${fontSize}
${color}
`;
render(
This is a Box
,
);
Main advantages
- Adds properties that you can use in your own themes.
- Quick setting responsive font-size, margin, padding, width and other css properties via props
- Typography Scalability
- Margin and padding scalability
- Support for any color palette
- Works with most css-in-js libraries, including styled-components and emotion
- Used by Rebass , Rebass Grid , and Priceline Design System
Connecting Themes
Above, I provided code example that uses ThemeProvider. We pass our theme to the provider, and the styled system accesses it through props.
An example of our topic
export const theme = {
/** Размер шрифтов */
fontSizes: [
12, 14, 16, 18, 24, 32, 36, 72, 96
],
/** Отступы и границы */
space: [
// margin and padding
0, 4, 8, 16, 32, 64, 128, 256
],
/** Общие цвета */
colors: {
UIClientError: '#ff6c00',
UIServerError: '#ff0000',
UITriggerRed: '#fe3d00',
UITriggerBlue: '#00a9f6',
UIModalFooterLightBlueGray: '#f3f9ff',
UIModalTitleDefault: colorToRgba('#5e6670', 0.4),
UICheckboxIconCopy: colorToRgba('#909cac', 0.2)
},
/** Размеры кнопок */
buttonSizes: {
xs: `
height: 16px;
padding: 0 16px;
font-size: 10px;
`,
sm: `
height: 24px;
padding: 0 24px;
font-size: 13px;
`,
md: `
height: 34px;
padding: 0 34px;
font-size: 14px;
letter-spacing: 0.4px;
`,
lg: `
height: 56px;
padding: 0 56px;
font-size: 20px;
`,
default: `
height: 24px;
padding: 0 30px;
font-size: 13px;
`,
},
/** Цвета кнопок */
buttonColors: {
green: `
background-color: #a2d628;
color: ${colorToRgba('#a2d628', 0.5)};
`,
blue: `
background-color: #507bfc;
color: ${colorToRgba('#507bfc', 0.5)};
`,
lightBlue: `
background-color: #10aee7;
color: ${colorToRgba('#10aee7', 0.5)};
`,
default: `
background-color: #cccccc;
color: ${colorToRgba('#cccccc', 0.5)};
`
}
}
styled system will try to find the value in the theme object based on the passed properties of the component. Deep nesting of properties is supported, if the transmitted value is not found in the topic, then the value is interpreted as is.
For example, we passed the component color = "red". There is no color.red value in the topic object, but the red value will be translated to css as red. So after transpilation in the inspector we will see
color: red;
Other examples of using topic values
// font-size: 24px (theme.fontSizes[4])
// margin: 16px (theme.space[3])
// color: #ff6c00 (theme.colors.UIClientError)
// background color (theme.colors.UITriggerBlue)
// width: 50%
Responsive styles
To quickly describe responsive properties, just pass an array of values
// responsive font size
// responsive margin
// responsive padding
Variants
The styled system allows us to define reusable objects in our topic that contain sets of colors, text styles, and so on. For example, in our topic presented above, we
use options for the sizes and colors of buttons.
/** Размеры кнопок */
buttonSizes: {
xs: `
height: 16px;
padding: 0 16px;
font-size: 10px;
`,
sm: `
height: 24px;
padding: 0 24px;
font-size: 13px;
`,
default: `
height: 24px;
padding: 0 30px;
font-size: 13px;
`,
},
/** Цвета кнопок */
buttonColors: {
green: `
background-color: #a2d628;
color: ${colorToRgba('#a2d628', 0.5)};
`,
blue: `
background-color: #507bfc;
color: ${colorToRgba('#507bfc', 0.5)};
`,
lightBlue: `
background-color: #10aee7;
color: ${colorToRgba('#10aee7', 0.5)};
`,
default: `
background-color: #cccccc;
color: ${colorToRgba('#cccccc', 0.5)};
`
}
Implementation of the option:
/** Для размеров кнопок */
export const buttonSize = variant({
/** Свойство компонента */
prop: 'size',
/** Свойство темы*/
key: 'buttonSizes'
});
/** Для цветов кнопок */
export const buttonColor = variant({
/** Свойство компонента */
prop: 'colors',
/** Свойство темы*/
key: 'buttonColors'
});
Button Component
/** Описание компонента */
export const Button = styled(Box.withComponent('button'))`
${buttonSize}
${buttonColor}
`;
Button.propTypes = {
...buttonSize.propTypes,
...buttonColor.propTypes,
}
An example of using a medium-sized blue button
A more detailed description and documentation of the styled system at the office. page on github
UPD: while writing an article, the styled system got its own page with documentation and examples https://styled-system.com/ .