shadcn.io is not affiliated with official shadcn/ui
When the pointer arrives or the button takes keyboard focus, a fill rises from the bottom edge like water in a glass, and drains when it leaves. The label above the waterline keeps its color and the part below it turns to the fill's text color, so it reads all the way through.
Use it on a form's submit or a primary call to action that sits on a quiet page; for a fill that slides in from the side of a pill, use the Pill Button. It starts as an outline button so the empty state is a frame, and it wraps the Button, so every variant and size works. The fill is a second copy of the label on a colored layer, uncovered by a rising clip-path in a CSS transition, with no animation library and no JavaScript. With reduced motion the fill fades in and out instead of rising.
Installation
Usage
import { LiquidButton } from "@/components/ui/liquid-button";<LiquidButton>Subscribe</LiquidButton>Demos
Duration
duration is how long the fill takes to rise, and to drain, in milliseconds; the default is 500. A short one suits a small button that's hovered often, a long one a large call to action that can take its time.
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 send button fills with the foreground color and a delete button with the destructive one. Icons in the label change color with the text.
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 fills the button as hover does, so people who tab see the same cue.
- Enter
- Activate the button.
- Space
- Activate the button.
FAQ
How does the fill work?
The button holds a colored layer with its own copy of the label, clipped to nothing. On hover a clip-path uncovers it from the bottom up, so the fill and the label's new color move as one edge.
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.
How do I make the fill rise slower?
Set duration in milliseconds; 500 is the default. The Duration demo shows 250 and 1200.
Why does it start as an outline button?
So the empty state reads as a frame waiting to fill. Pass any other variant to change it; the fill covers it the same way.
API Reference
LiquidButton
data-slot="liquid-button-fill"
children?ReactNode
The label, drawn again on the fill in fillForeground.
duration?number
How long the fill takes to rise, and to drain, in milliseconds.
- Default
500
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
Forwarded to the part.
--liquid-button-durationstring
The rise, and the drain (500ms).
--liquid-button-fillstring
The fill's color.
--liquid-button-fill-foregroundstring
The label's color on the fill.
Related
- Pro
Flip Button
Hover revealsHover reveals a second face
- Pro
Shine Button
SurfacesA light sweep instead of a fill
- Pro
Gradient Button
SurfacesColor that moves on its own
- Pro
Underline Button
Hover revealsThe quietest hover reveal
Loading Button
Progress & resultsWhat a submit shows next
- Pro
Pill Button
SurfacesRounded call to action