Slide to Unlock
A confirmation control that only fires once the thumb is dragged all the way, preventing accidental taps.
A mis-tap-proof control that only confirms once the thumb has been dragged all the way — a good fit for irreversible actions such as payments and deletions. Releasing before the threshold springs back, and on success the thumb snaps to the end and shows a checkmark, while the hint text on the track has a shimmer highlight sweeping across it. Arrow keys can advance it from the keyboard.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add slide-to-unlock.enSlide to Unlock is a React slide-to-confirm component built with Motion and Tailwind CSS. onConfirm only fires once the user drags the knob past a threshold, which makes it a common guard against accidental payments and deletions.
Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<SlideToUnlock/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
When to use
- "Slide to pay" confirmation on a mobile checkout page
- The last step of irreversible actions such as deleting an account or wiping data
- "Slide to complete order" or "confirm arrival" in delivery and ride-hailing apps
- Smart-home controls where commands like unlocking a door or disarming an alarm should take a deliberate gesture
- Not a good fit: async requests that need loading, success, or error states after submit; use Stateful Button instead. For a press-and-hold confirmation on desktop, see Hold to Confirm
Installation
npx webberui@latest add https://webberui.com/r/slide-to-unlock.en.jsonOr, once registries are configured in components.json, install it as @webberui/slide-to-unlock.
Usage
import { SlideToUnlock } from "@/components/ui/slide-to-unlock";
<SlideToUnlock
label="Slide to confirm payment"
successLabel="Payment confirmed"
onConfirm={() => submitPayment()}
/>Examples
Confirmation that can fire again
With resetDelay above 0, the knob returns to the start that many milliseconds after unlocking, which suits pages where users confirm more than once.
<SlideToUnlock
label="Slide to clock in"
successLabel="Clocked in"
resetDelay={2000}
onConfirm={() => recordCheckIn()}
/>Enable sliding only after consent
Bind disabled to form state; while disabled, neither dragging nor the keyboard has any effect.
"use client";
import * as React from "react";
import { SlideToUnlock } from "@/components/ui/slide-to-unlock";
export function DeleteAccount() {
const [agreed, setAgreed] = React.useState(false);
return (
<div className="space-y-4">
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
/>
I understand my data cannot be recovered
</label>
<SlideToUnlock
label="Slide to delete account"
successLabel="Deletion requested"
disabled={!agreed}
onConfirm={() => deleteAccount()}
/>
</div>
);
}Tune the threshold and width
The track fills its container by default; cap it with className. The closer threshold is to 1, the further users have to drag before it counts.
<SlideToUnlock
className="mx-auto max-w-xs"
threshold={0.95}
label="Slide to send transfer"
successLabel="Transfer sent"
onConfirm={() => submitTransfer()}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Slide to Unlock" | The shimmering hint text in the middle of the track |
successLabel | string | "Confirmed" | Text shown after a successful unlock |
threshold | number | 0.9 | The drag ratio (0 to 1) required to confirm; releasing before it springs back |
onConfirm | () => void | — | Called when the thumb reaches the end (exactly once per unlock) |
resetDelay | number | 0 | Delay before resetting automatically after success (milliseconds); 0 means it stays unlocked |
disabled | boolean | false | Disables interaction (both dragging and the keyboard) |
className | string | — | Merged onto the outermost track |
Accessibility
- The thumb is a button with
role="slider"that reports the progress percentage live througharia-valuenow/aria-valuetext - Full keyboard support:
→/↑advance,←/↓go back (10% each),Endunlocks immediately,Homereturns to zero - A successful unlock is announced through
aria-live="polite"with the success text - When the user has "reduce motion" enabled at the system level, the shimmer sweep is turned off and the spring back and the snap become near-instant positioning
FAQ
Does it work with the Next.js App Router?
Yes. The file already starts with "use client", so you can import it from a Server Component page as usual; function props such as onConfirm need to be passed from a client component.
How many times does onConfirm fire?
Once per unlock. With resetDelay at 0 (the default) the knob stays unlocked and won't fire again; set resetDelay and it can be slid again after it resets.
Can keyboard users operate it?
Yes. The knob is a button with role="slider". Arrow keys move it forward or back by 10%, End unlocks immediately, and Home resets it; reaching threshold or beyond counts as a confirmation.
Does it break when the width changes?
No. The component measures the track with ResizeObserver and updates the drag range, and an unlocked knob re-snaps to the end.
What are the dependencies?
motion, lucide-react, clsx, and tailwind-merge. If you'd rather skip the CLI, the Manual tab in the installation section walks you through copying the source.