Extending our CSS-in-JS to support style-component syntax
Tags: css, javascript, react, webdev
Published: 2022-08-24 07:11:00

In the [previous post](https://aniketjha.dev/build-your-own-emotion-like-css-in-js-library), we made our `css` emotion like function and in this blog post, we are going to extend our `css` function to support the following style-components syntax.

```jsx
const Button = styled('button')(
  {
    backgroundColor:  "blue",
    color: "white"
  }
)
```
A few things to note when exploring the API are:
```jsx
// On breaking into parts: 
const Button = // <-- Part: 3
styled('button') // <-- Part: 1
({ backgroundColor: 'blue' }) // <-- Part: 2

```
- Part 1: The `styled` function takes the `tagName` that has to be created i.e

```jsx
 styled('button') <-- 1

// is equivalent to

<button>
```

- Part 2: The `styled(tagName)` returns a function that accepts `style-object` which will be used to style this `tagName` element.

```jsx
({ backgroundColor: "blue" }) <-- Part 2

// is converted to 

css({ backgroundColor: "blue" }) 

// and passed to the component as

<button className={css(...)} />
```

- The complete call returns a React component `Button` that renders a `button` with a given style.

![Rendering a button using style-component like syntax](https://cdn.hashnode.com/res/hashnode/image/upload/v1661315488639/_062dWi86.png align="center")

From the above points, we can write a rough husk of our `styled` function

```jsx
// Part 1: styled('button'): element of type tagName to render
function styled(tagName) { 
  // Part 2: style('button')({ color: 'white' }) takes in the style object and applies these styles to `tagName=button` component

  return function applyStyles(styleObject) { 
      // Part 3: `Button` react component 
      return function Component(props) { 
          // ...styling and element creation... 
          // Mark: 1
      }
  }
}
```
Now in place **Mark: 1** we need to do the following:
- Create an element using `React.createElement` of type `tagName`
- Pass `style-object` into `css` function to generate name, as props may already contain some className so compose these className together.

```jsx
// continue from Mark: 1

const clonedProps = clone(props);
// a copy of props is required as by default react makes props immutable
// and if we want to modify any props we need to make a copy for our use

// compute a className for styleObject
const generatedClassName = css(styleObject);

// compose className 
const className = generatedClassName + props.className ? + ` ${props.className}` : '';

// reassign composed className
clonedProps.className = className;

// create element of type `tagName` with props = `clonedProps` and `style=generateClassName`
const element = React.createElement(tagName, clonedProps);

// The `element` is of type `tagName` and of `styles=styleObject` this is one we want to render

return element;
```

That is what the `style-components` version of our CSS-in-JS library looks like. `clone` function can be as simple as:

```jsx
const clone = (obj) => Object.assign({}, obj);
```
More reads on the CSS-in-JS:

- [Why CSS-in-JS?](https://aniketjha.dev/why-css-in-js)
- [CSS: Isolation vs Abstraction](https://aniketjha.dev/css-isolation-vs-abstraction)
- [Build your own emotion like CSS-in-JS library](https://aniketjha.dev/build-your-own-emotion-like-css-in-js-library)
- [Styler GitHub](https://github.com/vtechguys/styler)
- [Styler Codesandbox](https://codesandbox.io/s/styler-sd2xbl)