How to create a React.js(TypeScript) Reusable Custom Button Component with TailwindCSS.

Photo by Jess Bailey on Unsplash

How to create a React.js(TypeScript) Reusable Custom Button Component with TailwindCSS.

ยท

5 min read

So before we start, I would like to show you what the code for the reusable custom button is going to look like.

import React from 'react';

type ButtonType = 'button' | 'submit' | 'reset' | undefined;
interface Props {
  children: React.ReactNode;
  handleClick?: () => void;
  styles: string;
  type?: ButtonType;
  title: string;
  disabled?: boolean;
}

const Button = (props: Props) => {
  return (
    <button
      className={`${props.styles} ...`}
      type={props?.type}
      title={props.title}
      disabled={props.disabled}
      onClick={props?.handleClick}
    >
      {props.children}
    </button>
  );
};

export default Button;

Let's get started, and before driving into coding, we first have to install TailwindCSS, and Vite. For some of you that are new, TailwindCSS is a popular utility-first CSS framework that makes it easy to create modern, responsive, and highly customized user interfaces. It provides a set of pre-defined CSS classes that you can use to style your HTML elements without having to write custom CSS code from scratch, and that's the best thing about it, so don't worry we will soon speak in tailwind ๐Ÿ˜‚.

And Vite is a build tool for modern web development that aims to offer a faster and more streamlined development experience, in simple words. With Vite, it takes seconds to start our React.js(TypeScript) app faster, than the simple create-react-app.
But this tutorial is only focused on teaching you how to create a reusable custom button. So I will provide a link to install them, which is simple by the way.

Vite and TailwindCSS

Starting...

So we begin by defining how a button works in React.js, you see, it works by allowing us to interact with a website, which could be by linking to another page, toggling between light and dark mode, or showing pop-ups, and for submission after we fill a form. Almost 99.99% of every website out there uses buttons on its page.

Why Re-usable Components?

Imagine your website has a lot of buttons, that will by all means have a colour size, padding and margin given to you by a web designer or yourself, so let's say after implementing ten(10) buttons, you realised you have to make changes to the padding, now, what happens it that, you have to make those changes ten(10) times, which is time wasting and energy consuming, and less effective also.

So that's where re-usable components come in, so here is the general idea about it. You create a functional component then you pass some props(properties) to the re-usable component then display the component whether a <p> tag, <a> tag or a <button> tag in the webpage. So let's also assume that after adding ten(10) buttons added and you want to make changes to the size, padding or remove a margin, all you have to do is, go to the component and make the changes you want, then it affects all then ten(10) buttons at the same time.

Let's Start Building Our Component

Go to the link below to clone the project, or if you already have one started you're still good to go.

https://github.com/rockyessel/reusable_button/tree/starter

So in the src directory, we create a components folder, and then we create a Button.tsx file. Then we go to the App.tsx file and import the button over there.

Button.tsx

/* /components/Button.tsx  */

const Button = () => {
    return (
        <button></button>
    )
}

export default Button

App.tsx

/* App.tsx  */
import Button from './components/Button'

const App = () => {
    return (
        <main>
            <Button></Button>
        </main>
    )
}

export default App;

So every HTML element has an attribute, and for a button, the most commonly used attribute is type, disabled, title, class and more. But since this is a component that we want to dynamically add styles to it, and make it handle different functions pass to the onClick handler, we add:

  1. handleClick

  2. type

  3. title

  4. disabled

  5. styles - For adding custom styles to the default we will set later.

  6. children

So let's set the types,

type ButtonType = 'button' | 'submit' | 'reset' | undefined;
interface Props {
  children: React.ReactNode;
  handleClick?: () => void;
  styles: string;
  type?: ButtonType;
  title: string;
  disabled?: boolean;
}

So we are saying that with this line of code is that type ButtonType = 'button' | 'submit' | 'reset' | undefined; that we want the type? of the Button Component to either have a button or submit or reset as its type or be undefined if not specified.

Explaining the interface Props :

  • children: This a type that represents a React element, an array of React elements, or a string, number, or boolean

  • handleClick: This is a function that doesn't return any data, when called but can execute any function inside of it.

  • styles: Here the styles is a string, meaning if any data type apart from the string is used, we immediately get a type error. But we included this so, we can give custom styling to the button.

  • title: When a user hovers the cursor over the button, a tooltip appears with the name of the value we passed to the title.

  • disabled: This field expects a boolean value, if true, it makes the button unclickable, and if false vice-verser.

So now let's put all this together inside our Button Component

/* /components/Button.tsx  */

type ButtonType = 'button' | 'submit' | 'reset' | undefined;
interface Props {
  children: React.ReactNode;
  handleClick?: () => void;
  styles: string;
  type?: ButtonType;
  title: string;
  disabled?: boolean;
}

const Button = (props:Props) => {
    return (
        <button
        onClick={props?.handleClick}
        className={`${props.styles} px-3 py-2 rounded-lg hover:bg-violet-700 font-medium hover:ring-2 hover:border-2 border-2 border-transparent hover:border-black hover:ring-violet-700`}
        type={props?.type}
        title={props.title}
        disabled={props?.disabled}
        >
            {props.children}
        </button>
    )
}

export default Button

Now with this, we are done with creating a reusable dynamic button component that we can use throughout our application. But note that the className has some tailwind class in them, I added this because we to give the button a default styling, and then depending on where we want to add our custom styling, all we have to do is add the styling to our styles props.

Now, we go into our App.tsx, then add the necessary props to the button.

/* App.tsx  */
import Button from './components/Button'

const App = () => {
    return (
        <main>
            <Button
            handleClick={()=>{}}
            styles={'w-full bg-violet-500'}
            type={'button'}
            title={'Open modal'}
            disabled={false}
            >
                {/* children */}
                   Open modal
            </Button>
        </main>
    )
}

export default App;

Now this how our button looks like.

Now we source code and you can view the live web application here. Or you can visit here to see an implementation in one of my projects of the use button component being used.

And that's it, we're done. Now you can also create reusable components by yourself.

Did you find this article valuable?

Support Rocky Essel by becoming a sponsor. Any amount is appreciated!

ย