Site icon Shiva Pandey

Building design system with styled-components and styled-system II

This is a part 2 of how to use styled-component and styled system together to create React Components if you haven’t read the first part Read here. 

In the previous post I explained how you can create components easily by extending DOM elements. But I told you that creating components is like a lego where you can create small reusable components and attach them together to create a new bigger component. Styled-Components not only allows us to extend the DOM elements but also React components. Let’s try existing Button component to make few variants.

const ButtonPill = styled(Button)`
  border-radius: 24px;
  background: transparent;
  border: 1px solid;
  color: ${props => props.bg};
  border-color: ${props => props.bg};
`;

ButtonPill.defaultProps = {
  bg: "orange"
};

You can see how easily we created a new component that will make extend existing Button component with some additional styles. All the props passed to this button will eventually passed to the original button component whether or not you use them.

Note: We have a background transparent to prevent the original button component to set the background for this.

This is one way of extending component. But If there are very few style changes which can be easily modified through props this is not the right approach to take. The example above is not a ideal situation but given to you for the purpose of showing how you can extend your components. The right approach here will be make the original button component accept border radius and color also and extend it this way:

const ButtonPill = props => <Button {...props} borderRadius="24px" bg="transparent" color={props.bg} />

Remember to strictly follow the placements of props. If you place {…props} after you set attributes it can be replaced by new values. Since we know the key styles that define pill button are transparent background, colored text and a nice border radius, we keep them strict. When you create components you need to balance how much customizable you want it to be and how much originality you are preventing.

Styled system:

Writing those mini functions like ${props => props.bg ? props.bg: ‘orange’ }  can be very annoying when you see lots of repeated code with exactly same pattern. To avoid this we could create some functions that will do the exact same thing which can be reused and is easy to write. Styled system does exactly that. It has a collection of functions that will be resolved to styles within styled-components. One of the thing I like most about styled components is it provides us flexibility of passing various props to customize the behavior by just placing a single function. Let me show you an example:

import { color, fontSize, space } from "styled-system";

const Button = styled.button`
  ${color};
  ${fontSize};
  ${space};
  border: none;
  border-radius: 3px;
  font-weight: 500;
`;

Button.defaultProps = {
  bg: "orange",
  fontSize: 15,
  py: 10,
  px: 30,
  m: 20
};

See how we replaced background, color, padding, margin, fontSize with the functions from  styled-system. Style system now allows us to pass props with different key names. for e.g. if you add space from styled-system. it now allows you to use p (padding), px (padding horizontal), py (padding vertical), pt (padding top) , pb (padding bottom), pl (padding left), pr (padding right). You can imagine how much code you needed to write to have this kind of flexibility.  To read more about which method translate to which property in css you can refer to this table.

further optimization

You can now avoid lot of code and have greater flexibility for styles. Let’s reduce the code further and try to avoid repeating same things. When you write styles using style system you still end up repeating many functions again and again. Let’s suppose you need to add flex box support to a component. Let’s call that Column.

import styled from "styled-components";
import {
  space,
  flex,
  flexBasis,
  flexDirection,
  flexWrap,
  justifyContent,
  alignItems,
  alignSelf,
  alignContent
} from "styled-system";

const Column = styled.div`
  display: flex;
  ${space};
  ${flex};
  ${flexBasis};
  ${flexDirection};
  ${flexWrap};
  ${justifyContent};
  ${alignItems};
  ${alignSelf};
  ${alignContent};
`;

Here display: flex is hardcoded because this is a flex box component and it should always have display flex. Rest of the things are customizable. This looks perfect but what if you want to add flex properties to a image component? The code would be:

const Image = styled.image`
 display: flex;
 ${space};
 ${flex};
 ${flexBasis};
 ${flexDirection};
 ${flexWrap};
 ${justifyContent};
 ${alignItems};
 ${alignSelf};
 ${alignContent};
 ${width};
 ${height};
`;

If you look at the two components you can see there are so many things in common. Now, if you want to add flex properties to more components, you will end up repeating this things again and again. Let’s try to solve that. Styled components has a awesome feature that allows us to group styles. From the above example we can see that the repeating pattern is related to flex properties. So, creating a group of flex properties would benefit us.

import { css } from "styled-components";

const flexProperties = css`
 display: flex;
 ${space};
 ${flex};
 ${flexBasis};
 ${flexDirection};
 ${flexWrap};
 ${justifyContent};
 ${alignItems};
 ${alignSelf};
 ${alignContent};
`;

Now we have grouped all the related styles as flexProperties. So, now time to modify our Column and Image Component. Let’s refactor the code

const Column = styled.div`
 ${flexProperties};
`;

const Image = styled.div`
 ${flexProperties};
 ${size};
`;

You can see how we managed to reduce the code. The size style I am using here groups width and height together. You can group a lot of styles in similar way depending upon your project requirements.

This is for the second part of this series. In next series, I will explain how we can create theme objects to our styled components to cater our needs. I will also explain how you can create themes, responsive styles and variants like (warning, danger, info ) similar to bootstrap or other libraries without repeating similar code again and again. Part 3

Exit mobile version