Build Chakra UI IconButton component using react, typescript, styled-components and styled-system
Tags: react, typescript
Published: 2021-09-05 16:20:58

### Introduction

Let us continue building our chakra components using `styled-components` & `styled-system`. In this tutorial we will be cloning the Chakra UI `IconButton` & component.

- I would like you to first check the chakra docs for [icon-button](https://chakra-ui.com/docs/form/icon-button).
- We will use our `Button` component to create the `IconButton` component.
- All the code for this tutorial can be found [here](https://github.com/yaldram/chakra-ui-clone) under the **atom-form-button** branch.

### Prerequisite

Please check the previous post where we have completed the Button Component. Also please check the Chakra IconButton Component code [here](https://github.com/chakra-ui/chakra-ui/blob/main/packages/button/src/icon-button.tsx).

In this tutorial we will -

- Create a IconButton component.
- Create story for the IconButton component.

### Setup

- We will continue to work in the **atom-form-button** from the previous tutorial.

- Under the `components/form/button` folder create a new file `icon-button.tsx`.

- So our folder structure stands like - **src/components/atoms/form/button**.

### IconButton Component

- Let me first paste the code -

```tsx
import * as React from "react";

import { Button, ButtonProps } from "./button";

type Omitted =
  | "leftIcon"
  | "isFullWidth"
  | "rightIcon"
  | "loadingText"
  | "iconSpacing";

export interface IconButtonProps extends Omit<ButtonProps, Omitted> {
  icon?: React.ReactElement;
  isRound?: boolean;
  "aria-label": string;
}

export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
  (props, ref) => {
    const {
      icon,
      children,
      isRound,
      "aria-label": ariaLabel,
      ...delegated
    } = props;

    const element = icon || children;
    const buttonChildren = React.isValidElement(element)
      ? React.cloneElement(element as any, {
          "aria-hidden": true,
          focusable: false,
        })
      : null;

    return (
      <Button
        ref={ref}
        aria-label={ariaLabel}
        padding="0"
        borderRadius={isRound ? "9999px" : "0.375rem"}
        {...delegated}
      >
        {buttonChildren}
      </Button>
    );
  }
);
```

- The above code is self-explanatory. We have removed all the rightIcon, leftIcon, iconSpacing props from the type, instead we are just allowing the icon prop which will be our icon element.

- We added `isRound` prop, for circle shaped buttons.

- Because `IconButton` uses `Button` all the props are inherited and we can continue to pass `colorScheme`, `variant` and `s` (size).

### Story

- With the above our `IconButton` component is completed, let us create a story.
- Under the `src/components/atoms/form/button/button.stories.tsx` file we add the below story code.

```tsx
export const ButtonIcon = {
  render: () => (
    <Stack>
      <IconButton aria-label="Search database" icon={<SearchIcon />} />
      <IconButton
        colorScheme="blue"
        aria-label="Search database"
        icon={<SearchIcon />}
      />
      <IconButton
        variant="outline"
        colorScheme="teal"
        aria-label="Send email"
        icon={<EmailIcon />}
      />
      <IconButton
        colorScheme="teal"
        aria-label="Call Segun"
        s="lg"
        icon={<PhoneIcon />}
      />
    </Stack>
  ),
};
```

- Now run `npm run storybook` check the stories. Under the Playground stories check the controls section play with the props, add more controls if you like.

### Build the Library

- Under the `/button/index.ts` file and paste the following -

```tsx
export * from "./button";
export * from "./icon-button";
```

- Now `npm run build`.

- Under the folder `example/src/App.tsx` we can test our `Wrap` component. Copy paste the following code and run `npm run start` from the `example` directory.

```tsx
<Stack m="md">
  <IconButton aria-label="Search database" icon={<SearchIcon />} />
  <IconButton
    colorScheme="blue"
    aria-label="Search database"
    icon={<SearchIcon />}
  />
  <IconButton
    variant="outline"
    colorScheme="teal"
    aria-label="Send email"
    icon={<EmailIcon />}
  />
  <IconButton
    colorScheme="teal"
    aria-label="Call Segun"
    s="xs"
    icon={<PhoneIcon />}
  />
  <IconButton
    colorScheme="teal"
    aria-label="Call Segun"
    s="sm"
    icon={<PhoneIcon />}
  />
  <IconButton
    colorScheme="teal"
    aria-label="Call Segun"
    s="md"
    icon={<PhoneIcon />}
  />
  <IconButton
    colorScheme="teal"
    aria-label="Call Segun"
    s="lg"
    icon={<PhoneIcon />}
  />
</Stack>
```

### Summary

There you go guys in this tutorial we created IconButton component just like chakra ui. You can find the code for this tutorial under the **atom-form-button** branch [here](https://github.com/yaldram/chakra-ui-clone). In the next tutorial we will create `Image` component. Until next time PEACE.