Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Buttons

Pro

Slide To Confirm Button for React

A pill with a handle to drag across it, so a stray tap can't trigger the action. For React with Base UI, when a payment or a delete should take a deliberate gesture.

Framework
UI library

Drag the handle along the track. The fill follows it and the label fades. Let go past threshold, 90% of the way by default, and onConfirm runs, the handle shows a check, and it slides back after a moment. Let go earlier and it slides back with nothing done.

Use it for high-stakes actions on touch screens, such as paying, sending to everyone or deleting, where a tap is too easy to make by accident. On a desktop page a Long Press Button or a confirmation dialog is often simpler. It wraps the Button, so variant works as usual and size sets the track's height; the handle is as tall as the track. Dragging writes one CSS variable, the progress from 0 to 1, and the handle and the fill follow it with a CSS translate while the label fades, with no animation library. The handle follows the finger even with reduced motion, but the slide back is a jump instead of a glide.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import {
  SlideToConfirmButton,
} from "@/components/ui/slide-to-confirm-button";
<SlideToConfirmButton onConfirm={pay}>Slide to pay</SlideToConfirmButton>

Demos

Threshold

threshold is how much of the track the handle has to cross, from 0 to 1. Half the track is enough to unlock; 1 asks for the whole way, for something you'd rather people think about.

Preview width

Destructive

The track takes any variant and size: the handle is drawn in the label's color, so it matches, and it's as tall as the track. Here a wider, taller track (className="w-72", size="xl") deletes files, and resetDelay keeps the handle at the end for 1.5 seconds so the result has time to register.

Preview width

Accessibility

It's a button named by its label, such as Slide to pay $24.00. Dragging isn't the only way in: Enter and Space confirm it, and so does a screen reader's activate command, with the handle sliding across to show it. A mouse click on the track does nothing, so the gesture stays deliberate for pointers. The handle and its icons are hidden from assistive tech.

Enter
Confirm.
Space
Confirm.

FAQ

How do I change the words on the track?

Pass them as children: <SlideToConfirmButton>Slide to send</SlideToConfirmButton>. The default is Slide to confirm. The label is also the button's accessible name.

How far does someone have to slide?

90% of the track by default. Set threshold between 0 and 1: lower is easier, 1 needs the full length. The Threshold demo shows 0.5 and 1.

Can keyboard and screen reader users confirm it?

Yes. Enter, Space and a screen reader's activation confirm it without dragging, and the handle slides across to show it. The button tells them apart from a mouse click because their click has no pointer behind it (its detail is 0).

What happens after it confirms?

The handle moves to the end and shows a check, rests there for resetDelay (800 milliseconds by default), then slides back. Navigate or show a message from onConfirm. The track has data-state="confirmed" while it rests, for styling.

How do I make the track wider or narrower?

Pass a width in className, such as w-72; the default is w-64, and it never grows past its container. The height follows size. Keep it wide enough that the threshold can't be crossed by accident.

Does it work right to left?

Yes. In a right-to-left layout the handle starts on the right and slides left, and the arrow points that way.

What happens with reduced motion?

The handle still follows the finger, since that's the gesture itself. Going back after a release, or across after a key press, is instant instead of a glide.

API Reference

SlideToConfirmButton

data-slot="slide-to-confirm-button-track"

PropType
children?ReactNode

The label on the track; it fades as the handle crosses it.

Default
"Slide to confirm"
clickEffect?boolean

Shrink a little on press, as the Button does. Off, so the track holds still under a drag.

Default
false
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
onConfirm?() → void

Called when the handle is let go past threshold, or when the button is pressed with Enter or Space. A click on the track doesn't confirm.

Returns
void
resetDelay?number

How long the handle rests at the end after confirming, in milliseconds, before it slides back.

Default
800
threshold?number

How much of the track the handle has to cross to confirm, from 0 to 1. Let go before it and the handle slides back.

Default
0.9
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

"confirmed" when confirmed is true, otherwise "idle".

CSS variableType
--slide-to-confirm-button-progressstring

How far the handle is, 0 to 1 (set while dragging).

All 35 buttons