React JS styled-components: A fancy theming feature for styling your React components

React JS styled-components: A fancy theming feature for styling your React components

We basically build CSS classes to style our UI elements / nodes in HTML or any other frontend technology. Suppose, we have to add 10 buttons on a page with different colors, text, height, width...What we do?? We just use bootstrap or input button types and write CSS for all the buttons. Isn't it?? Quite boring!!! Thanks, to react styled components for being a SAVIER here!! Let's dig in more to learn - What are styled-components and how we can use them?

What are styled components?

Styled-components uses tagged template literals to style the components. It removes the mapping between components and styles which means that when you’re defining your styles you’re actually creating a normal ReactJS component, that has your styles attached to it.

Why to use styled components?

Being a developer, we have a special quality of being LAZY and finding smarter, shorter ways of dealing with complexities :) That's where styled components makes our work easier and healthier too!!

styled-components are the result of wondering how we could enhance CSS for styling React component systems.

Below are few of the attractive advantages -

  • Automatic critical CSS: styled-components keeps track of which components are rendered on a page and injects their styles and nothing else, fully automatically. Combined with code splitting, this means your users load the least amount of code necessary.

  • No class name bugs: styled-components generates unique class names for your styles. You never have to worry about duplication, overlap or misspellings.

  • Easier deletion of CSS: it can be hard to know whether a class name is used somewhere in your codebase. styled-components makes it obvious, as every bit of styling is tied to a specific component. If the component is unused (which tooling can detect) and gets deleted, all its styles get deleted with it.

  • Simple dynamic styling: adapting the styling of a component based on its props or a global theme is simple and intuitive without having to manually manage dozens of classes.

  • Painless maintenance: you never have to hunt across different files to find the styling affecting your component, so maintenance is a piece of cake no matter how big your codebase is.

Let's drill through some styling

styled-components utilizes tagged template literals to style your components by removing the mapping between components and styles.

Below is a example that creates two simple components, a wrapper and a title, with some styles attached to it -

// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: gold;
`;
const Paragraph = styled.p`
  font-size: 1em;
  text-align: center;
  color: white;
`;
// Create a Wrapper component that'll render a <section> tag with some styles
const Wrapper = styled.section`
  padding: 4em;
  background: black;
`;
// Use Title and Wrapper like any other React component – except they're styled!
render(
  <Wrapper>
    <Title>
      Welcome to AJ's Blog!
    </Title>
    <Paragraph>
      Let's learn about React styled-components
    </Paragraph>
  </Wrapper>
);

r1.PNG

Adapting based on props

We can pass a function to a styled component's template literal to adapt it based on its props.

Let's create a button component has a primary state that changes its color, text transformation based on props. When setting the prop to true, we are swapping out its background, text, and text transformation.

const Button = styled.button`
  /* Adapt the properties based on props */
  background: ${props => props.primary ? "red" : "white"};
  color: ${props => props.primary ? "white" : "red"};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid red;
  border-radius: 3px;
  text-transform: ${props => props.uppercase ? "uppercase" : (props.lowercase ? "lowercase" : (props.capitalize ? "capitalize" : "lowercase"))}
`;

render(
  <div>
    <Button capitalize>aj</Button>
    <Button uppercase primary>aj</Button>
    <Button lowercase primary>aj</Button>
  </div>
);

r3.PNG

Extending Styles

Quite frequently you might want to use a component, but change it slightly for a single case. Now, you could pass in an interpolated function and change them based on some props, but that's quite a lot of effort for overriding the styles once.

To easily make a new component that inherits the styling of another, just wrap it in the styled() constructor. Here we use the button from the last section and create a special one, extending it with some color-related styling:

// The Button from the last section without the interpolations
const Button = styled.button`
  color: red;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid red;
  border-radius: 3px;
`;

// A new component based on Button, but with some override styles
const GreenButton = styled(Button)`
  color: green;
  border-color: green;
`;

render(
  <div>
    <Button>Normal React Button</Button>
    <GreenButton>Extended React Button</GreenButton >
  </div>
);

r4.PNG

We can see that the new GreenButton still resembles Button, while we have only added two new rules.

In some cases you might want to change which tag or component a styled component renders. This is common when building a navigation bar for example, where there are a mix of anchor links and buttons but they should be styled identically.

For this situation, we have an escape hatch. You can use the "as" polymorphic prop to dynamically swap out the element that receives the styles you wrote:

const Button = styled.button`
  display: inline-block;
  color: red;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid red;
  border-radius: 3px;
  display: block;
`;

const GreenButton = styled(Button)`
  color: green;
  border-color: green;
`;

render(
  <div>
    <Button>Normal Button</Button>
    <Button as="a" href="/">Link with Button styles</Button>
    <GreenButton as="a" href="/">Link with Green Button styles</GreenButton>
  </div>
);

How do Styled Components work within a component?

If you're familiar with importing CSS into your components (e.g. like CSSModules) you'll be used to doing something like this:

import React from 'react'
import styles from './styles.css'

export default class Counter extends React.Component {
  state = { count: 0 }

  increment = () => this.setState({ count: this.state.count + 1 })
  decrement = () => this.setState({ count: this.state.count - 1 })

  render() {
    return (
      <div className={styles.counter}>
        <p className={styles.paragraph}>{this.state.count}</p>
        <button className={styles.button} onClick={this.increment}>
          +
        </button>
        <button className={styles.button} onClick={this.decrement}>
          -
        </button>
      </div>
    )
  }
}

Note that we added a "Styled" prefix to StyledCounter so that the React component Counter and the Styled Component StyledCounter don't clash names but remain easily identifiable in the React Developer Tools and Web Inspector.

Define Styled Components outside of the render method

It is important to define your styled components outside of the render method, otherwise it will be recreated on every single render pass. Defining a styled component within the render method will thwart caching and drastically slow down rendering speed, and should be avoided.

Write your styled components the recommended way:

const StyledWrapper = styled.div`
  /* ... */
`

const Wrapper = ({ message }) => {
  return <StyledWrapper>{message}</StyledWrapper>
}

Instead of:

const Wrapper = ({ message }) => {
  // WARNING: THIS IS VERY VERY BAD AND SLOW, DO NOT DO THIS!!!
  const StyledWrapper = styled.div`
    /* ... */
  `

  return <StyledWrapper>{message}</StyledWrapper>
}

It just feels nice. It isn't game-changing, but it brings a little bit of joy.

Misc tips and tricks

Phew! We've covered few basic level “big ideas” I wanted to share, but before I wrap up, I have a few smaller tidbits I think are worthwhile. Let's go through them.

The 'as' prop

React developers have a reputation for being ignorant of semantic HTML, using <div> as a catch-all.

r2.PNG

A fair criticism of styled-components is that it adds a layer of indirection between the JSX and the HTML tags being produced. We need to be aware of that fact, so that we can account for it!

Every styled-component you create accepts an as prop which'll change which HTML element gets used. This can be really handy for headings, where the exact heading level will depend on the circumstance:

// `level` is a number from 1 to 6, mapping to h1-h6
function Heading({ level, children }) {
  const tag = `h${level}`;
  return (
    <Wrapper as={tag}>
      {children}
    </Wrapper>
  );
}
// The `h2` down here doesn't really matter,
// since it'll always get overwritten!
const Wrapper = styled.h2`
  /* Stuff */
`;

It can also come in handy for components that can either render as buttons or links, depending on the circumstance:

function LinkButton({ href, children, ...delegated }) {
  const tag = typeof href === 'string'
    ? 'a'
    : 'button';
  return (
    <Wrapper as={tag} href={href} {...delegated}>
      {children}
    </Wrapper>
  );
}

Semantic HTML is very important, and the as prop is a crucial bit of knowledge for all developers building with styled-components.

Hope you find this post helpful!! Please feel free to leave your views/insights below in comments section. You can connect with me on LinkedIn

Thanks for reading!

Did you find this article valuable?

Support Amit Jethwani by becoming a sponsor. Any amount is appreciated!