ui-049

Slide to Confirm Button

£7 or the whole Vault, £79.20

A slide to confirm button for irreversible actions: flick or drag the thumb to confirm, with spring return, async pending state and a button fallback.

intermediate
7 more details
draggablemicro-interactionstate-transitionkeyboard-navigationspring-physicsvelocity-reactivemask-reveal

This element reads better at your own screen size than in the frame below:

Updated

About this component

Give important actions a deliberate final step that feels physical. Drag the thumb across and release, or flick it: a fast throw toward the end completes from partway, while a short release springs back with a small damped overshoot. The thumb wipes its label as it passes and meets resistance just before the end stop.

Read the full effect overview

Completion runs your own async confirm function with a pending spinner, then shows success or returns to the start with an error line. A keyboard-operable thumb and a two-step button alternative reach the same outcome, and each instance mounts through a small API with complete and cancel events, light and dark themes and reduced-motion support.

Slide to Confirm Button - UI component preview

What's included

7 items
  • Flick to complete, using release velocity from the last 100ms
  • Damped spring return and resistance at the end stop
  • Label wipes and trail fills with the thumb
  • Async confirm with pending, success and error states
  • Keyboard slider thumb plus a two-step button alternative
  • Mount API with reset, complete, destroy and events
  • Light and dark themes with reduced-motion support

Perfect for

4 use cases
  • Publishing a release after a final review
  • Approving a payment or payout
  • Deleting an account or a production resource
  • Confirming a deliberate action on touch screens

How it works

2 sections

A throw, not a range input

Pointer samples from the last 100ms give the release velocity, so a quick flick completes early and a finger that stopped does not. Returns run on a small spring from that velocity, and travel past the threshold is damped before the end stop.

Your action decides the outcome

Completion calls your confirm function and waits on its promise: a spinner while pending, a drawn check on success, or a spring back to the start with an error line on failure. Keyboard and button paths use the same completion.

Difficulty Intermediate
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this UI element's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid UI element

Purchase to unlock the code.

Buying Slide to Confirm Button opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£7 Standard license, unlimited projects

Browse UI elements

Or the whole library: the Vault, £79.20, one payment.

Documentation

What's Included

  • index.html: working demo and component markup.
  • assets/style.css: responsive component styles and two complete themes.
  • assets/script.js: readable source; assets/script.min.js: generated compact source.
  • Flick to complete: release velocity is measured over the last 100ms, so a fast throw toward the end completes from partway while a finger that stopped before lifting does not.
  • Spring return: a short release returns on a damped spring with a few pixels of overshoot, and the thumb meets resistance past the threshold before the end stop.
  • Progress feedback: the thumb wipes the label as it passes, the trail fills behind it, and the arrow swaps to a spinner and then a drawn check.
  • Async confirmation: your confirm function's promise drives pending, success, or a return to start with an error line.
  • A two-step button alternative and a keyboard-operable thumb, cancel, disabled and reset states, reduced-motion support, multiple instances per page.

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Copy the [data-drag-confirm] section from index.html into your page.

3. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

Without a confirm function the control succeeds straight away, so it also works as a plain intent gesture.

Using It With Your Own Design

Keep the data-confirm-* hooks inside each [data-drag-confirm] root; each root is an independent instance. Change the heading, tag and messages to suit the action. The demo's confirm is a timer that resolves (or rejects while "Fail next" is on); connect your own request and keep your own server validation.

The toolbar and .stage layout are demo furniture. Remove them and the global page CSS when integrating; keep the component's positioned track, handle dimensions and touch-action: none on the handle. The alternative and Cancel buttons are part of the accessible component, so keep both.

API

Mount, in your application JavaScript after DOM ready:

Code snippet omitted: it ships with the download.

Option Default Description
confirm none Called once per completion with { source, root }. Its return value (or promise) is awaited. A rejection returns the thumb to start and shows messages.statusError.
threshold data-threshold or 0.88 Release past this fraction of travel completes. Clamped to 0.5 to 1.
flingVelocity data-fling-velocity or 800 A release moving right at this speed or faster completes, if the thumb has covered at least 30% of travel and the throw would carry it past the threshold.
disabled data-disabled or false Initial disabled state.
messages see DEFAULT_MESSAGES in script.js Any of the label, status and button strings. statusError may be a function receiving the rejection.

mount returns the same instance if the root is already mounted.

Method Description
reset() Returns to idle and cancels any pending confirmation's outcome. Keeps the disabled setting.
complete() Runs the completion path as if the user had confirmed (source: 'api'). Returns a promise of true on success, false otherwise.
setDisabled(bool) Changes availability and resets.
getState() idle, dragging, armed, ready, pending, confirmed or disabled. Also mirrored on data-state.
destroy() Removes listeners and the ticker, reverts GSAP work, and restores the original inline styles, attributes and text.

SlideConfirm.get(root) returns a root's instance or null.

Events

Both bubble from the root.

Code snippet omitted: it ships with the download.

Auto-mount and earlier versions

Any [data-drag-confirm] root your code has not mounted by the end of the page's first task is mounted automatically from its data attributes, so markup from the earlier version keeps working. Mount it yourself on DOMContentLoaded (as above) to pass options, or add data-manual to leave it alone until you do. root.dragConfirm still points at the instance and drag-confirm:confirm still fires alongside slideconfirm:complete; note that it now fires after confirm succeeds rather than at the moment of release.

Keyboard & Accessibility

Input Behaviour
Tab / Shift+Tab Reaches the thumb, then the native action buttons.
Arrow Right / Up, Arrow Left / Down Moves the thumb 10% of travel. Page Up / Page Down move 25%, Home and End go to either end.
Enter / Space on the thumb First press slides it to the end and arms it; second press confirms.
Escape Returns an armed or keyboard-moved thumb, cancels an active drag, or cancels the button confirmation step.
Enter / Space on "Use button instead" First activation offers "Confirm release"; second confirms. Cancel returns and restores focus.

The thumb is a role="slider" with aria-valuenow as percentage of travel and an aria-valuetext that says what Enter will do. Moving focus away from a keyboard-moved thumb returns it, so an armed control is never left behind. While pending, the root carries aria-busy="true" and the controls are aria-disabled rather than disabled, so focus is never dropped. A polite role="status" line announces instructions, pending, success and the error. Reduced motion keeps every input path and applies end states immediately: no spring, no spinner rotation, no glow.

How It Works

Pointer events drive the thumb directly, with pointer capture so the gesture survives leaving the track. Each move is recorded with its timestamp; on release only the samples from the last 100ms count toward velocity, so a stopped finger releases at zero. Pointer travel maps to thumb travel one to one up to the threshold, then at half rate into the end stop, with a few pixels of exponential rubber past either end.

Returns and completions run on a small spring integrated on GSAP's ticker (stiffness 320, damping ratio 0.68, fixed 4ms substeps so it behaves the same at any frame rate), starting from the release velocity. That is why a thumb caught mid-return picks up where it is. The label is masked with a gradient that follows the thumb's leading edge (--reveal on the track). Completion hands off to confirm; a stale result from before a reset() is ignored.

Themes

Light is the default. Set the theme on the component root in your application:

On your component's opening tag:

Code snippet omitted: it ships with the download.

The demo sets data-variant="light" or data-variant="dark" on <body> and honours ?variant=dark. Both use the same markup and script. Re-value --ground, --ground-2, --raised, --hover, --ink, --ink-2, --ink-3, --line, --line-strong, --accent, --accent-ink, --accent-wash, --danger, --shadow, --font, --radius, --radius-sm and --radius-xs to match your product. Keep text contrast at least 4.5:1, including --danger for the error line.

Customisation

  • Change .drag-confirm's maximum width to fit your layout; the handle remeasures automatically.
  • Lower flingVelocity for a looser throw, raise it for a stricter one; raise threshold to demand a longer slow drag.
  • The spring and resistance constants (STIFFNESS, the damping ratio, END_RESISTANCE, RUBBER) sit together at the top of script.js. Keep the damping ratio above about 0.6 or the return starts to read as a bounce.
  • Re-value --confirm-glow in both theme blocks to customise the completion glow.
  • Use data-state for extra styling and the events for application logic.

Requirements

  • GSAP 3.12+, core only.
  • A browser with Pointer Events, ResizeObserver and CSS masks.
  • No framework or build step.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.