shadcn.io is not affiliated with official shadcn/ui
Two thin rings leave the button's edge and fade as they spread, one after the other, in a loop. They take the button's corners at every size, pill included.
Use it for the single action you most want taken on a screen: start a trial, take the tour, finish setup. Keep it to one per page, and turn it off once it has done its job; a pulse that never stops turns into noise. For a glow that answers the pointer instead, use the Neon Button. It wraps the Button, so variant and size work as usual. The rings are CSS keyframes the install adds to your stylesheet, with no animation library. When the system asks for reduced motion they stop and one ring stays, still and faint.
Installation
Usage
import { PulseButton } from "@/components/ui/pulse-button";<PulseButton>Start free trial</PulseButton>Demos
Stop After a Click
pulse turns the rings on and off. Here they stop once the button has been pressed, since it has been noticed by then. Driving it from state works the same way after a timeout, or once the section has scrolled out of view.
Color
The rings follow the variant: the primary color by default and the destructive color on a destructive button. pulseColor takes any CSS color for another one, here a quiet var(--muted-foreground) ring on an outline button.
Duration
duration is one ring's spread and fade in milliseconds; the default is 2000, and the second ring always runs half a cycle behind the first. A fast pulse, 1200 here, feels urgent; a slow one, 3200, is a gentle reminder.
Accessibility
The rings are decoration and hidden from assistive tech: the button is announced and activated as any Button. They hide while the button is disabled, so a pulse never points at something that can't be pressed.
- Enter
- Activate the button.
- Space
- Activate the button.
FAQ
How do I stop the pulse once it has been seen?
Set pulse={false}. Keep it in state and turn it off after the first click, a few seconds in, or when the user scrolls past, as in the Stop After a Click demo.
How do I change the rings' color?
Pass pulseColor, any CSS color such as var(--muted-foreground) or a hex code. Without it the rings are the primary color, or the destructive color on the destructive variant.
Can I make it pulse faster or slower?
Set duration in milliseconds; 2000 is the default. The second ring always runs half a cycle behind the first, as the Duration demo shows.
Do the rings follow rounded or pill buttons?
Yes. Each ring is a line on the button's own edge, with its corners, that grows outward, so it keeps the button's shape, pill included, at every size. It grows a little more up and down than across, so a wide button gets an even margin all round.
Will a pulse that loops forever slow the page down?
No. The keyframes only change each ring's scale and opacity, which the browser can hand to the compositor: no repaint, no re-render and no JavaScript while it runs.
Why are the rings cut off?
They spread a few pixels past the button. A parent with overflow: hidden and no room around the button cuts them; give it some padding.
API Reference
PulseButton
data-slot="pulse-button-rings"
children?ReactNode
The label; the rings pulse out around it.
duration?number
How long one ring takes to spread and fade, in milliseconds. The second ring is always half a cycle behind the first.
- Default
2000
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
pulse?boolean
Run the rings. Turn it off once the button has been noticed: after the first click, or a few seconds in.
- Default
true
pulseColor?string
The rings' color, any CSS color. By default the primary color, or the destructive color on the destructive variant.
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.
--pulse-button-colorstring
The rings' color.
--pulse-button-durationstring
One ring's spread and fade (2s).
--pulse-button-scalestring
How far a ring grows, across and down (1.1 1.35; 1.35 on an icon button).
Related
- Pro
Glow Border Button
Glow & lightA continuous glow, no rings
- Pro
Neon Button
Glow & lightA steady halo in primary
Record Button
Progress & resultsPulses while recording
- Pro
Shimmer Button
SurfacesA sweep of light to draw the eye
Ripple Button
Motion & feedbackRings on press, not on a loop
Magnetic Button
Motion & feedbackInvites the click on hover