Simple hamburger button in react-typescript and tailwind CSS
Tags: react, typescript, tailwindcss
Published: 2022-08-02 10:17:00

Hello all 👋

Today I will be creating a hamburger menu within `react`, `typescript` and `tailwind css`.

First things first, before we start we will be needing a few things.

1. Working machine with an IDE or text editor
2. Working react environment with `typescript` and `tailwind` support. (I recommend [vite](https://vitejs.dev/))
3. Coffee or drink of your choice. (I am going with Kofola)

## Preparing props and methods

So before we actually start typing our component, I would like to create an interface for it.
For those who don't know what `interface` is, basically it just is a block of code, that we use to tell us how are objects shaped.

```ts
// file: ~/components/hamburger/Hamburger.tsx

export interface HamburgerProps {
	/** Callback function, which should be executed on click */
	onClick: () => void;

	/** Initial state of our button */
	isInitiallyOpen?: boolean;
}
```

As you can see, we don't need much there. If you are fancy enough through, you can extend it with for example `ButtonHTMLAttributes<HTMLButtonElement>` with this your component will inherit every property and methods of react button component.

## Component structure

```tsx
// file: ~/components/hamburger/Hamburger.tsx
...

export function Hamburger(props: HamburgerProps) {
    const { onClick, isInitiallyOpen } = props;
    const [isOpen, setIsOpen] = useState<boolean>(isInitiallyOpen ?? false);

    const handleClick = () => {
        setIsOpen(prev => !prev);
        onClick();
    }

    return (
        <button onClick={handleClick} type="button" className={``}>
            <div className={``}/>
            <div className={``}/>
            <div className={``}/>
        </button>
    );
}
```

So there is the basic structure of our component. As you can see it's pretty straight forward, we just have a button with three `div`s and a simple `onClick` handler.

## Styling the component

```tsx
// file: ~/components/hamburger/Hamburger.tsx
...

export function Hamburger(props: HamburgerProps) {
    ...

    return (
        <button onClick={handleClick} type="button" className={`w-8 h-8 flex justify-around flex-col flex-wrap z-10 cursor-pointer`}>
            <div className={`bg-black block w-8 h-[0.35rem] rounded transition-all origin-[1px]`}/>
            <div className={`bg-black block w-8 h-[0.35rem] rounded transition-all origin-[1px]`}/>
            <div className={`bg-black block w-8 h-[0.35rem] rounded transition-all origin-[1px]`}/>
        </button>
    );
}
```

Next, we add the effect itself.

```tsx
// file: ~/components/hamburger/Hamburger.tsx
...

export function Hamburger(props: HamburgerProps) {
    ...

    return (
        <button onClick={handleClick} type="button" className={`w-8 h-8 flex justify-around flex-col flex-wrap z-10 cursor-pointer`}>
            <div className={`... ${isOpen ? 'rotate-45' : 'rotate-0'}`}/>
            <div className={`... ${isOpen ? 'translate-x-full bg-transparent' : 'translate-x-0'}`}/>
            <div className={`... ${isOpen ? 'rotate-[-45deg]' : 'rotate-0'}`}/>
        </button>
    );
}
```

Hooray! With this done, we should be able to actually see the component in its final form.


![Hamburger effect in action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1bcuuytptjxsqnmji12y.gif)

## Final code

```tsx
// file: ~/components/hamburger/Hamburger.tsx

export interface HamburgerProps {
	/** Callback function, which should be executed on click */
	onClick: () => void;

	/** Initial state of our button */
	isInitiallyOpen?: boolean;
}

export function Hamburger(props: HamburgerProps) {
	const { onClick, isInitiallyOpen } = props;
	const [isOpen, setIsOpen] = useState<boolean>(isInitiallyOpen ?? false);

	const handleClick = () => {
		setIsOpen((prev) => !prev);
		onClick();
	};

	return (
		<button
			onClick={handleClick}
			type="button"
			className={`w-8 h-8 flex justify-around flex-col flex-wrap z-10 cursor-pointer`}
		>
			<div
				className={`bg-black block w-8 h-[0.35rem] rounded transition-all origin-[1px] ${
					isOpen ? 'rotate-45' : 'rotate-0'
				}`}
			/>
			<div
				className={`bg-black block w-8 h-[0.35rem] rounded transition-all origin-[1px] ${
					isOpen ? 'translate-x-full bg-transparent' : 'translate-x-0'
				}`}
			/>
			<div
				className={`bg-black block w-8 h-[0.35rem] rounded transition-all origin-[1px] ${
					isOpen ? 'rotate-[-45deg]' : 'rotate-0'
				}`}
			/>
		</button>
	);
}
```



Using this component is very simple, all it requires is a callback function.

I like to use this setup with sidebar menu. So I have `useState` with current state of sidebar and I have function to change the state. I use both of these as props for `<Hamburger/>` component.

I hope I helped or entertained you enough, and please excuse the quality of this post, it is my first post here at `dev.to`.