Creating a Gradient Component in React From Design Tokens
Tags: javascript, react, webdev, design
Published: 2022-01-20 16:08:45

If you're not familiar with [design tokens](https://www.michaelmang.dev/blog/introduction-to-design-tokens), they are simply representations of design specifications in code.

![Creating a Gradient Component in React From Design Tokens](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8q5cbu96xnlznjr6ou0w.png)

By "representations," it is meant that they are key-value pairs that represent design specifications.

Generally speaking, there are two types of design tokens:

1. "Simple" tokens - Representations of valid _values_ of the design system. These tokens usually cover the colors, typography, spacing, etc. of the design system (i.e. `color-red-500`, `font-bold`, etc.).

2. "Component" tokens - Representations of the design specs for a component/element (i.e. `component-button-background-color`).

![Creating a Gradient Component in React From Design Tokens](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sk9x7g2ps2p3gysf2z4k.png)

With a [design tokens pipeline](https://www.michaelmang.dev/blog/managing-and-exporting-design-tokens-with-style-dictionary), you can write out design tokens in JSON format, and then translate those "raw"/JSON design tokens into formatted tokens (JavaScript modules, CSS variables, SASS variables, etc.).

With that background in mind, imagine that a design system had "simple" design tokens defining valid colors.

Here's the JSON representation:

```jsonc
{
  "color": {
    "red-50": "#FFC3C2",
    "red-100": "#FFAFAD",
    // ...etc
  }
}
```

Now, imagine that a design tokens pipeline formats the JSON into the following JavaScript modules:

```jsx
export colorRed50 = "#FFC3C2";
export colorRed100 = "#FFAFAD";
// ...etc
```

And, let's say these tokens can be consumed in an application via an npm package:

```jsx
// SomeComponent.jsx

import * as tokens from "@some/design-system/tokens";

function SomeComponent() {
  const style = { color: tokens.colorRed50 };
  return <div style={style}>Some Component</div>
}
```

Now, given such a setup, how can we programmatically create gradients when given two color tokens?

![Creating a Gradient Component in React From Design Tokens](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0zhns61di1x2xjxcik2a.png)
 
Here's one way:

```jsx
// SomeComponent.jsx

import * as tokens from "@some/design-system/tokens";

function SomeComponent() {
  const style = {
    background: `
      linear-gradient(
        45deg,
        ${tokens.colorRed50},
        ${tokens.colorRed100}
      )
    `,
  };
  return <div style={style}>Some Component</div>
}
```

Ok, but is there a way that we can refactor this?

Well, we could create a helper function that returns the gradient when providing the `from` and `to` values:

```jsx
// get-gradient.js

export default function getGradient(from, to) {
  return `linear-gradient(45deg, ${from}, ${to})`;
}

// SomeComponent.jsx

import * as tokens from "@some/design-system/tokens";

import getGradient from './get-gradient.js';

function SomeComponent() {
  const style = {
    background: getGradient(
      tokens.colorRed50,
      tokens.colorRed100,
    ),
  };
  return <div style={style}>Some Component</div>
}
```

This refactor doesn't save in lines of code, but it does guarantee that gradients will be created the same so long as they are created through the `getGradient` helper function.

What if we refactored one step further and allowed the gradient to be applied to any child component via a wrapper component?

```jsx
// Gradient.jsx

import { Children, cloneElement } from 'react';

function getGradient(from, to) {
  return `linear-gradient(45deg, ${from}, ${to})`;
}

export default function Gradient({ children, from, to }) {
  return Children.map(children, (child) => {
    return cloneElement(child, {
      style: {
        ...child.props.style,
        background: getGradient(from, to),
      },
    });
  });
}

// SomeComponent.jsx

import * as tokens from "@some/design-system/tokens";

import AnotherComponent from './AnotherCompoent.jsx';
import Gradient from './Gradient.jsx';

function SomeComponent() {
  return (
    <Gradient from={tokens.colorRed50} to={tokens.colorRed100}>
      <AnotherComponent />
    </Gradient>
  );
}
```

By using `Children` and `cloneElement`, the `Gradient` component clones the child element and applies the gradient.

🎊 Awesome! Now, we have a pattern for applying a gradient via a wrapper component in React!