Creating Variants of React Component
Published: 2021-09-26 15:58:56


So recently i've been working on building react components with StorybookJS. For those who don't know what Storybook is ,Storybook is a JavaScript tool that allows developers to create organised UI systems making both the building process and documentation more efficient and easier to use.

With that said , i would like to share a common design pattern that i learned from building these components, and that is creating variants of a single component through the use of props. 

*Do note that i'm using ChakraUI as my UI library

In this example we take a look at building a simple button component. Starting with the Button function

```javascript
export function ReactButton(props) {
  let {children} = props;

  return (
    <Button>
      {children}
    </Button>
  );
}
```

Following that , we add propTypes to establish our variants, you can definitely do without this step but it helps to ensure we're using the right data type

```javascript
ReactButton.propTypes = {
  variant: PropTypes.arrayOf(
  PropTypes.oneOf(["primary,secondary,outline,danger"])
  ),
};

export function ReactButton(props) {
  let {children} = props;

  return (
    <Button>
      {children}
    </Button>
  );
}
```

Now for the game changer, we make use of CSS to enable to the browser to display what we want want it to display. Using a switch statement we set the base styles for different variants

```javascript
 let baseStyles = {},
    invertStyles = {},
    stretchedStyles = {};

switch (variant) {
    case "primary":
      baseStyles = {
        backgroundColor: "brand1.primary.400",
        color: "#fff",
        _hover: {
          backgroundColor: "brand1.primary.500",
        },
      };
     break;
    case "secondary":
      baseStyles = {
        backgroundColor: "brand1.secondary.400",
        color: "#fff",
        _hover: {
          backgroundColor: "brand1.secondary.500",
        },
      };
     break;
    case "outline":
      baseStyles = {
        backgroundColor: "transparent",
        color: "brand1.secondary.300",
        borderColor: "brand1.secondary.300",
        _hover: {
          color: "brand1.secondary.500",
          borderColor: "brand1.secondary.500",
        },
      };
     break;
    case "danger":
      baseStyles = {
        backgroundColor: "brand1.danger.400",
        color: "#fff",
        _hover: {
          backgroundColor: "brand1.danger.500",
        },
      }
      break;

```
You will notice i created an empty object for  inverted and stretched, keep reading on to see how we implement those.

With that we set our default variant to primary, and establish some props like invert and stretched and give them a boolean value

```javascript
let {
    children,
    variant = "primary",
    invert = false,
    stretched = false,
  } = props;
```

Now we can go ahead and add stylings for our props that we declared (invert and stretched).

```javascript
switch (variant) {
    case "primary":
      baseStyles = {
        backgroundColor: "brand1.primary.400",
        color: "#fff",
        _hover: {
          backgroundColor: "brand1.primary.500",
        },
      };
      if (invert) {
        invertStyles = {
          backgroundColor: "brand1.primary.50",
          border: "0.25rem solid #ffe8ae",
          color: "#969696",
          _hover: {
            backgroundColor: "brand1.primary.100",
          },
        };
      }
      if (stretched) {
        stretchedStyles = {
          width: "100%",
          justifyContent: "space-between",
        };
      }
      break;

    case "secondary":
      baseStyles = {
        backgroundColor: "brand1.secondary.400",
        color: "#fff",
        _hover: {
          backgroundColor: "brand1.secondary.500",
        },
      };
      if (invert) {
        invertStyles = {
          backgroundColor: "brand1.secondary.50",
          border: "0.25rem solid #c4c9ef",
          color: "#969696",
          _hover: {
            backgroundColor: "brand1.secondary.100",
            color: "#fff",
          },
        };
      }
      if (stretched) {
        stretchedStyles = {
          width: "100%",
          justifyContent: "space-between",
        };
      }
      break;

    case "outline":
      baseStyles = {
        backgroundColor: "transparent",
        color: "brand1.secondary.300",
        borderColor: "brand1.secondary.300",
        _hover: {
          color: "brand1.secondary.500",
          borderColor: "brand1.secondary.500",
        },
      };
      if (invert) {
        invertStyles = {
          color: "#c9c9c9",
          borderColor: "#c9c9c9",
          _hover: {
            color: "#fff",
            borderColor: "#fff",
          },
        };
      }
      if (stretched) {
        stretchedStyles = {
          width: "100%",
          justifyContent: "space-between",
        };
      }
      break;

    case "danger":
      baseStyles = {
        backgroundColor: "brand1.danger.400",
        color: "#fff",
        _hover: {
          backgroundColor: "brand1.danger.500",
        },
      };
      if (invert) {
        invertStyles = {
          backgroundColor: "brand1.danger.50",
          border: "0.25rem solid #feb6b9",
          color: "#969696",
          _hover: {
            backgroundColor: "brand1.danger.100",
            color: "#fff",
          },
        };
      }
      if (stretched) {
        stretchedStyles = {
          width: "100%",
          justifyContent: "space-between",
        };
      }

      break;
```

Now that we have our complete styles in place and in a conditional statement , let us look at how we can use this styles in our component.

By spreading our stylings into the component through the object spread operator. Take note on the order in which the styles are added.

```javascript
  return (
    <Button
      {...baseStyles}
      {...props}
      {...invertStyles}
      {...stretchedStyles}
    >
      {children}
    </Button>
  );
}
```
Now about the order in which we have placed our props , baseStyles first followed by props then invertStyles and lastly stretchedStyles. The order is very important as the latter props on the list will take precedence over the styles of the earlier props on the list. Thats why we have baseStyles first , this give the developer the flexibility to deviate from the baseStyles.

To demonstrate, i will show 4 different buttons using the variant="danger" and the invert and stretched props

```javascript 
<Button variant="danger">Danger Button</Button>
```
![Screenshot 2021-09-26 at 11.51.50 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjzh4kbxzg6rdwcyiidm.png)

```javascript 
<Button variant="danger" stretched>Danger Button</Button>
```
![Screenshot 2021-09-26 at 11.52.48 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p44q5d5j44j3t0ivxehj.png)

```javascript 
<Button variant="danger" invert>Danger Button</Button>
```
![Screenshot 2021-09-26 at 11.53.45 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yd8hiurtxvwdnrhcpv06.png)

```javascript 
<Button variant="danger" invert stretched>Danger Button</Button>
```
![Screenshot 2021-09-26 at 11.54.29 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kui0714t0q8xp6sn88z0.png)
 
Thats all folks , i hope this helps you as much as it has helped me. If theres any way i can improve on this i would really love to hear it. Drop a comment below.