10th

Mar

2022

A Simple way to keep Styled Components Clean

If you're using styled-components and like me you're a fan of keeping the css blocks clean and concise, you may want to add in some helpers to grab parts of your theme you'll use over and over again. Things like colours, spacing, zIndexes or even props that you want to use.

Here's a small example of a theme file:

// theme.ts
const colours = {
  green: '#00F',
  white: '#FFF',
  orange: '#CC5500'
}

type ThemeColour = typeof color;
export type BorderRadiusKeys = 'small' | 'medium' | 'large';
type BorderRadius = Record<BorderRadiusKeys, string>;

export type Theme = {
  colours: ThemeColour,
  spacingValue: number,
  radius: BorderRadius
}

const spacingValue = 4;
const radius = {
  'small' : '4px',
  'medium': '8px',
  'large': '12px',
};

const theme: Theme = {
  colours,
  radius,
  spacingValue
}

I've set some colours, a spacing value for padding, margin etc and a border-radius property that helps keep things consistent across your codebase. Below in the helper file that uses lodash.get to pull the props out of your theme object and then do something with them.

// helpers.ts
import get from 'lodash.get';
import { BorderRadiusKey, Theme } from './helpers';

type ThemeProp = {
  theme: Theme
}

export const colour = (name: keyof Theme['Colours']) => ({theme}: ThemeProp) => get(theme.colours, name);
export const spacing = (multiplier: number) => ({theme}:ThemeProp) => `${get(theme,'spacingValue') * multiplier}px`;
export const radius = (size: BorderRadiusKey) => ({theme}: ThemeProp) => get(theme.radius, size)};

Finally here's an example React component that is using styled.div along with the helpers to keep things clean and nicely readable.

// some-component.tsx
import React from 'react';
import styled from 'styled-components';
import { colour, radius, spacing } from './helpers';

const Wrapper = styled.div`
  border: 1px solid ${color('green')};
  padding: ${spacing(5)};
  border-radius: ${radius('medium')};
`;

export const SomeComponent: React.FC = (
   <Wrapper>
    ...
   </Wrapper>
 );

I love having helper methods that are clear and concise and make use of partial application to help tidy things up. The helper functions could be further DRY-ed up and it's always advisable to write tests too.

I've made a Github gist with these files (with better syntax highlighting that my current blog is capable of rendering at the mo) and I've also included a sample test there to show how easy it is to test.