DEV Community

Arsalan Ahmed Yaldram
Arsalan Ahmed Yaldram

Posted on

Build Chakra UI IconButton component using react, typescript, styled-components and styled-system

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.
  • We will use our Button component to create the IconButton component.
  • All the code for this tutorial can be found here 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.

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 -
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>
    );
  }
);
Enter fullscreen mode Exit fullscreen mode
  • 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.
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>
  ),
};
Enter fullscreen mode Exit fullscreen mode
  • 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 -
export * from "./button";
export * from "./icon-button";
Enter fullscreen mode Exit fullscreen mode
  • 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.

<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>
Enter fullscreen mode Exit fullscreen mode

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. In the next tutorial we will create Image component. Until next time PEACE.

Discussion (0)