Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Buttons

Free

Icon Button for React

An icon-only toggle button that fills its icon and bursts with particles when it turns on, for like, bookmark and star actions. For React with Base UI, when a small toggle deserves a moment of feedback.

Framework
UI library

Pressing the button turns it on: the icon fills in its active color and pops, and a ring and six dots burst out around it. Pressing it again turns it off and empties the icon. The state is exposed as aria-pressed, so it's a real toggle.

Use it for like, favorite, bookmark, star or follow actions that flip one thing on and off. It keeps its own state, or you control it with active and onActiveChange to store the result. For a button that confirms a copy rather than a choice, use the Copy Button. It wraps the Button, as a round ghost icon button by default, so variant, pill and the icon sizes work. The fill is a CSS transition, and the pop and the burst are CSS keyframes, which the install adds to your stylesheet; a press that turns it on swaps them between two names, which restarts them, with no re-mount. With reduced motion there's no burst and no pop, and the icon still fills.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Usage

import { HeartIcon } from "lucide-react";
import { IconButton } from "@/components/ui/icon-button";
<IconButton aria-label="Like" icon={<HeartIcon aria-hidden="true" />} />

Demos

Controlled

Pass active and onActiveChange to keep the state yourself, for example to save it or to update a count. onActiveChange gets the new state on each press. Here the like count goes up and down with the heart.

Preview width

Color

activeColor takes any CSS color and tints the filled icon and the burst; the default is var(--primary). Theme variables such as var(--destructive) or var(--foreground) follow light and dark mode. Hover and focus tint the empty icon in the same color, as a hint of what a press does.

Preview width

Without the Burst

animate={false} keeps the fill and drops the pop, the ring and the dots, for a dense list or a toolbar where many toggles sit side by side.

Preview width

Accessibility

The button has no text, so aria-label is required: it says what the button does, such as Like or Bookmark. It's announced as a toggle button, with aria-pressed saying whether it's on. The icon and the burst are hidden from assistive tech. Enter and Space toggle it, and focus tints the icon as hover does.

Enter
Turn the button on or off.
Space
Turn the button on or off.

FAQ

What can I pass as the icon?

Any icon element, such as a Lucide icon: icon={<HeartIcon aria-hidden="true" />}. Its outline is filled in activeColor when the button is on, so outline icons work best.

How do I save the like when it changes?

Control it: pass active and update it from onActiveChange, which gets the new state. Without active the button keeps its own state, starting from defaultActive. The Controlled demo keeps a count.

How do I make the heart red?

Pass activeColor="var(--destructive)". Any CSS color works, but a theme variable follows light and dark mode. The Color demo shows three.

Can I turn off the burst?

Yes, with animate={false}. The icon still fills and empties, as in the Without the Burst demo.

Does the burst play when the page loads with the button on?

No. It plays only when a press turns the button on, so a list of items people already liked loads quietly.

Why is aria-label required?

An icon has no name a screen reader can read, so without a label the button would be announced as just a button. The prop's type makes it required.

Which sizes does it take?

The Button's icon sizes, from icon-xs to icon-xl; icon-md is the default. The icon scales with the size.

What happens with reduced motion?

No burst and no pop. The icon still fills, so the on state is as clear as ever.

API Reference

IconButton

data-slot="icon-button-icon"

PropType
active?boolean

Whether the button is on (pressed), to hold that state yourself.

defaultActive?boolean

Whether the button starts on, when it keeps its own state.

Default
false
onActiveChange?(active: boolean) → void

Called with the new state each time the button is pressed.

Parameters

active – boolean

Returns
void
iconReactNode

The icon, such as <HeartIcon /> from lucide-react: its outline fills in activeColor when on.

activeColor?string

The color of the filled icon and its burst, any CSS color.

Default
"var(--primary)"
animate?boolean

Play the burst (a ring and a spray of dots) and the pop when a press turns the button on. Without it the icon still fills.

Default
true
focusableWhenDisabled?boolean

Whether the button should be focusable when disabled.

Default
false
nativeButton?boolean

Whether the component renders a native <button> element when replacing it via the render prop. Set to false if the rendered element is not a button (for example, <div>).

Default
true
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

AttributeType
data-state?string

"on" when on is true, otherwise "off".

CSS variableType
--icon-button-colorstring

The filled icon's and the burst's color.

All 35 buttons