Three concepts of the styled-components library
Tags: react, styledcomponents, webdev
Published: 2022-07-25 18:49:03

## Introduction

Lately, I've been playing with [styled-components](https://styled-components.com/). It is a CSS-in-JS library that uses [tagged template literals](https://codeburst.io/javascript-what-are-tag-functions-97682f29521b). I want to talk about three concepts that I got puzzled by: **`Interpolation`**, **`GlobalStyle`** and **`ThemeProvider`**.

## What is Interpolation?

Interpolation is adapting a component based on the props passed to it; meaning, you can inject values through props. For example:

```javascript
const MockElement = styled.div`
  --size: ${(props) => (props.big ? '100px' : '50px')};
  width: var(--size);
  height: var(--size);
  background-color: yellowgreen;
`;

render(
  <div>
    // This renders a 50x50 square, because there was no "big" prop
    <MockElement />
    // This renders a 100x100 square, because "big" was passed
    <MockElement big />
  <div>
)
```

So you can use props as truthy values. What about custom values? That works too!

```javascript
const MockElement = styled.div`
  background-color: ${props => props.color ? props.color : 'yellowgreen'};

  --size: ${(props) => (props.big ? '100px' : '50px')};
  width: var(--size);
  height: var(--size);
`;

render(
  <div>
    // This renders a blue square
    <MockElement color='blue'/>
    // This renders... no color??
    <MockElement color />
  <div>
)
```

Styled props are truthy by default, but since no value was passed, nothing gets rendered. To use the default value with this technique, you either skip the prop entirely, or you pass a `null`.

But **BEWARE!** You must pass a function when interpolating a value, or the code breaks. Something like the following wouldn't work:

```javascript
const MockElement = styled.div`
  background-color: ${props.color}; /* It must be a function */
`;
```

Must the function be inline? No! You can simply pass any function as a callback:

```javascript
function declaredFunction (props) {
  let scale = `${props.factor * 50}px`
  return scale
}

const MockElement = styled.div`
  --size: ${declaredFunction};
  width: var(--size);
  height: var(--size);
  background-color: ${props => props.color ? props.color : 'yellowgreen'};
`;

render(
  <div>
    // This renders a 150x150, yellowgreen square
    <MockElement big color={null} factor={3}/>
  <div>
)
```

This marks the end of exploring `interpolation`. On to the next!

## What is GlobalStyle?

Self-explanatory as the name is, a GlobalStyle component is used to define general styling rules for the application. **A close comparison would be using an `index.css` file that gets imported and bundled before all other stylesheets**, thus being overwritten by css modules that follow it later.

Using a global style is fairly simple! First, you must create the `GlobalStyle.js` file, like so:

```javascript
import { createGlobalStyle } from 'style-components';

const GlobalStyle = createGlobalStyle`
  /* Insert global styling here */
`;

export default GlobalStyle;
```

Then, put the component...anywhere, really. At least, in the few tests I did, I put the component anywhere within the project and it worked just fine. However, for the sake of organization, I've put in my routing system (with react-router), like so:

```javascript
# App.js

import GlobalStyle from './utils/GlobalStyle';

function App() {
  return (
    <BrowserRouter>
      <GlobalStyle />
      <Routes>
        {/*The routes and elements go here*/}
      </Routes>
    </BrowserRouter>
  );
}
```

Cool! On to the final topic: `ThemeProvider`.

## What is ThemeProvider?

ThemeProvider is a source of universal props to all its children. You must put the component at the root of your project, if you want all components to have access to it.

So, if you use `App.js` as your root, you could do something like:

```javascript
#App.js
import { ThemeProvider } from 'styled-components';

const themeObject = {
  button : {
    primary : {
      background: 'lightblue',
      color: 'white',
    },
    secondary: {
      /* other keywords*/
    }
  }
}

function App() {
  return (
    <ThemeProvider theme={themeObject}>
      <CoolButton />
    </ThemeProvider>
  );
}
```

That `themeObject` becomes accessible to all objects that are children of `ThemeProvider`. You use the `theme` prop through `interpolation`, like this:

```javascript
#CoolButton.styled.js
import styled from 'styled-components';

const CoolButton = styled.button`
  background-color: ${props => props.theme.button.primary.background};
  /* As seen above and below, you just need to access the string from the theme object */
  color: ${props => props.theme.button.primary.color};
`
```

You can also combine all three components, by making `GlobalComponent` a child of `ThemeProvider` and interpolating values as needed. One useful example is setting the font family.

```javascript
# theme.js

const theme = {
  heading: "Cool Heading",
  subHeading: "Cute Heading"
};

export default theme;
```

```javascript
# GlobalStyle.js

import { createGlobalStyle } from 'styled-components';
import coolFontPath from './font-file1.woff';
import cuteFontPath from './font-file2.woff';

const GlobalStyle = createGlobalStyle`
  @font-face {
    font-family: 'Cool Heading';
    src: url(${coolFontPath};
  }

  @font-face {
    font-family: 'Cute Heading';
    src: url(${cuteFontPath};
  }

  h1 {
    font-family: ${props => props.theme.heading};
  }

  span.subheading {
    font-family: ${props => props.theme.subHeading}
  }
`
export default GlobalStyle;
```

```javascript
# App.js

import GlobalStyle from './GlobalStyle.js';
import theme from './theme.js';
import { ThemeProvider } from 'styled-components';

const App = () => {
  return (
  <ThemeProvider theme={theme}>
    <h1>I belong to the Cool Heading family</h1>
    <span className='subheading'>
      I belong to the Cute Heading family
    </span>
  </ThemeProvider>
  );
}
```

## Summary

So there you have it! This was the exploration of three important concepts of the styled-library: `Interpolation`, `GlobalStyling` and `ThemeProvider`. Hope it was of use!