---
title: HamburgerIcon
description: An animated hamburger menu icon that transitions between menu and close states with smooth CSS animations
---

```tsx
'use client';

import { useState } from 'react';

import { HamburgerIcon } from '@/ui/HamburgerIcon';

export function HamburgerIconDemo() {
  const [isActive, setIsActive] = useState(false);

  return (
    <button
      onClick={() => setIsActive(!isActive)}
      className="p-4 rounded hover:bg-gray-100"
      aria-label={isActive ? 'Close menu' : 'Open menu'}
    >
      <HamburgerIcon isActive={isActive} />
    </button>
  );
}
```

## Installation

Using the CLI:

```bash
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/hamburger-icon.json
```

Or manually, copy the following code into `/ui/hamburger-icon.tsx`:

```tsx
import clsx from 'clsx';
import type { ComponentPropsWithoutRef, FunctionComponent } from 'react';

interface Props extends ComponentPropsWithoutRef<'span'> {
  isActive?: boolean;
}

export const HamburgerIcon: FunctionComponent<Props> = ({
  className,
  isActive = false,
  ...attrs
}) => {
  const before = clsx(
    'before:absolute before:left-0 before:top-0 before:block before:h-2 before:w-24 before:bg-current before:opacity-100 before:transition-transform before:duration-500 before:content-[""] before:cursor-pointer',
    { 'before:translate-y-[-6px]': !isActive, 'before:translate-y-0 before:rotate-45': isActive },
  );

  const after = clsx(
    'after:absolute after:left-0 after:top-0 after:block after:h-2 after:w-24 after:bg-current after:opacity-100 after:transition-transform after:duration-500 after:content-[""] after:cursor-pointer',
    { 'after:translate-y-[6px]': !isActive, 'after:translate-y-0 after:-rotate-45': isActive },
  );

  return (
    <span
      data-name="HamburgerIcon"
      {...attrs}
      className={clsx(
        'menu-icon cursor-pointer',
        'color-current relative isolate shrink-0 h-24 w-24 block outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',
        className,
      )}
      data-testid={isActive ? 'HamburgerIcon-active' : 'HamburgerIcon'}
    >
      <span
        className={clsx(
          'absolute left-1/2 top-1/2 block h-2 w-24 -translate-x-1/2 -translate-y-1/2 transition-[background] duration-500 cursor-pointer',
          { 'bg-current': !isActive, 'bg-transparent': isActive },
          before,
          after,
        )}
      />
    </span>
  );
};
```

## Usage

```tsx showLineNumbers
import { useState } from 'react';
import { HamburgerIcon } from '@/docs/lib/ui/hamburger-icon';

export function Component() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);

  return (
    <button
      onClick={() => setIsMenuOpen(!isMenuOpen)}
      aria-label={isMenuOpen ? 'Close menu' : 'Open menu'}
    >
      <HamburgerIcon isActive={isMenuOpen} />
    </button>
  );
}
```

## API Reference

### HamburgerIcon

| Prop        | Type                               | Default     | Description                                                                                                           |
| ----------- | ---------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------- |
| `isActive`  | `boolean`                          | `false`     | Controls the icon's state. When `true`, displays an "X" (close icon). When `false`, displays the hamburger menu icon. |
| `className` | `string`                           | `undefined` | Additional CSS classes to apply to the container span element. Merged with default styles.                            |
| ...         | `ComponentPropsWithoutRef<"span">` | -           | All standard HTML span element attributes are supported (e.g., `id`, `onClick`, `data-*`, `aria-*`).                  |

## Notes

- **Animated Transitions**: The icon smoothly animates between hamburger and X states with a 500ms transition duration using CSS transforms
- **Color Control**: Uses `currentColor` for the icon color, so it inherits the text color from its parent element
- **Fixed Size**: The icon has a fixed size of 24px × 24px (w-24 h-24 in Tailwind) with three lines that are 2px thick
- **Cursor Pointer**: The icon has `cursor-pointer` class applied by default, indicating it's meant to be clickable
- **Data Attributes**: Sets `data-name="HamburgerIcon"` and `data-testid` based on the `isActive` state for testing purposes
- **CSS-Only Animation**: The animation is purely CSS-based using pseudo-elements (::before, ::after) and the middle line, providing smooth performance
- **Accessibility**: Should be wrapped in a button element with appropriate `aria-label` that describes the current state (e.g., "Open menu" or "Close menu")
