shadcn.io is not affiliated with official shadcn/ui
The Pill Button is round at both ends and starts as an outline. When the pointer arrives or the button takes keyboard focus, a fill slides in from the side the text starts on, its leading edge curved like the pill itself, and slides back out when it leaves. The label turns to the fill's text color exactly where the fill passes, and a soft inset highlight along the fill's bottom edge makes it read as a curved surface.
Use it for the action a page is built around: Get started, Subscribe, Book a demo. For a fill that rises from the bottom of a square button, use the Liquid Button. It wraps the Button, so every variant and size works, with wider padding at each size so the ends have room. The fill is a second copy of the label on a colored layer, uncovered by a rounded clip-path in a CSS transition, with no JavaScript and no animation library. With reduced motion the fill fades in and out instead of sliding.
Installation
Usage
import { PillButton } from "@/components/ui/pill-button";<PillButton size="lg">Get started</PillButton>Demos
Color
fillColor is the fill and fillForeground the label's color where the fill covers it, each any CSS color; by default they're the primary color and its foreground. Set them together so the covered label stays readable. Here a demo booking fills with the foreground color, and a Cancel plan button with the destructive one, so it never wears the brand color.
Duration
duration is how long the fill takes to slide across, and back, in milliseconds; the default is 450. A quick slide suits a small button that's hovered often, a slower one a large hero button. The fill covers any variant at rest, such as secondary here.
Accessibility
The button is announced and activated as any Button. The fill's copy of the label is hidden from assistive tech, so the label is read once. Keyboard focus slides the fill in as hover does, so people who tab through the page see the same cue.
- Enter
- Activate the button.
- Space
- Activate the button.
FAQ
How does the fill slide in?
The button holds a colored layer with its own copy of the label, clipped to nothing by a clip-path with round corners. On hover the clip opens from the start side to the end, so the fill grows with a curved leading edge, and the label's new color moves with it.
How do I change the fill color?
Pass fillColor, and fillForeground for the label on it, such as var(--foreground) and var(--background). The Color demo shows two.
Why does it start as an outline?
So the empty pill reads as a frame waiting to fill. Pass any other variant to change the look at rest; the fill covers it the same way.
Why is it wider than my other buttons?
It adds padding at the ends at every size, because a fully round end eats into the label's room. Pass px-* in className to match a neighbor exactly.
Which side does the fill come from in a right-to-left layout?
The right, where the text starts. In a left-to-right layout it comes from the left.
API Reference
PillButton
data-slot="pill-button-fill"
children?ReactNode
The label, drawn again on the fill in fillForeground.
duration?number
How long the fill takes to slide across, and back, in milliseconds.
- Default
450
fillColor?string
The fill's color, any CSS color.
- Default
"var(--primary)"
fillForeground?string
The label's color where the fill covers it, any CSS color: pick one
that reads on fillColor.
- Default
"var(--primary-foreground)"
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.
--pill-button-durationstring
The slide across, and back (450ms).
--pill-button-fillstring
The fill's color.
--pill-button-fill-foregroundstring
The label's color on the fill.
Related
- Pro
Depth Button
Motion & feedbackAnother tactile, physical surface
- Pro
Stitch Button
SurfacesHandmade texture on the button
- Pro
Shine Button
SurfacesAdds a light sweep on hover
- Pro
Glass Button
SurfacesTranslucent surface for heroes
Arrow Button
Hover revealsSays the action moves forward
- Pro
Gradient Button
SurfacesLouder fill for the main CTA