webdevpuneet.com

Slide to Confirm — Drag Slider HTML CSS JS Snippet

Slide to Confirm · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

<div class="sc-wrap">
  <div class="sc-track" id="scTrack">
    <div class="sc-fill" id="scFill"></div>
    <span class="sc-label" id="scLabel">Slide to confirm payment</span>
    <button class="sc-handle" id="scHandle" aria-label="Slide to confirm">
      <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
    </button>
  </div>
  <button class="sc-reset" id="scReset">↺ Reset</button>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Transform-based drag
Handle uses translateX and the fill uses scaleX, so the motion is compositor-smooth and survives Tailwind/React export (which animate transforms, not raw width).
Jump-free grab
down records the pointer-to-handle offset, so grabbing the handle anywhere does not snap it to the cursor — it tracks naturally.
Live-measured bounds
maxPos() reads the track and handle sizes on each use, so the end threshold stays correct even if the layout resizes.
Window-level tracking
Move and release listeners on window keep the drag alive when the pointer leaves the track mid-slide.
Threshold commit
Release within a few pixels of the end triggers complete(); anything short animates back, enforcing a deliberate full slide.
Locked confirmed state
On confirm, a done flag blocks further dragging so the action cannot double-fire, and the track turns green with a check label.
Snap-back animation
An .animate class adds transition: transform only for snap-back and confirm, keeping the active drag perfectly 1:1.
Touch + mouse
Pointer coordinates are read from e.touches or e.clientX, so it works identically on phones and desktops.

About this UI Snippet

Slide to Confirm — Drag-to-Commit Handle, Snap-Back & Confirmed Lock State

Screenshot of the Slide to Confirm snippet rendered live

"Slide to confirm" is the deliberate-action control: instead of a one-tap button that is easy to hit by accident, the user must drag a handle all the way across a track to commit. It is the right pattern for irreversible or high-stakes actions — sending a payment, deleting an account, dispatching an order, unlocking a device. This snippet implements it in plain HTML, CSS, and vanilla JavaScript with full touch and mouse support: a draggable handle, a fill that tracks the drag, snap-back if released early, and a locked confirmed state.

Transform-based dragging (smooth everywhere)

The handle moves with transform: translateX and the green fill grows with transform: scaleX from a left origin — both are compositor-friendly transforms, so the drag is smooth and, importantly, the animation survives a Tailwind/React export unchanged (utility frameworks animate transforms but not raw width). During an active drag the position is set directly with no transition for 1:1 finger tracking; only the snap-back and confirm use a .animate class that adds transition: transform.

Accurate pointer math

On press, down records the offset between the pointer and the handle's current position, so the handle does not jump to the cursor. move then sets the position as pointerX − offset, clamped between 0 and maxPos() (the track width minus the handle and padding, measured live so it stays correct if the layout changes). The move and up listeners live on window, so dragging continues even if the pointer leaves the track.

Threshold, snap-back, and lock

On release, up checks whether the handle reached the end (within a few pixels of maxPos()). If it did, complete() locks the control: it snaps the handle fully right, fills the track green, changes the label to "✓ Payment confirmed", and reveals a reset link. If it did not, the handle and fill animate back to the start — the action is *not* committed, which is the whole point of requiring a full, intentional slide. A done flag blocks further dragging once confirmed so the action cannot fire twice.

Replayable

A reset button (hidden until confirmation) calls resetSlide, animating everything back to the initial state so you can demo it repeatedly or re-arm the control after, say, a failed transaction.

Because the commit happens only in complete(), wiring it to a real action is a one-line change. Pair this with a confirm dialog for typed confirmations, an order summary before payment, or a download button for progress-based actions.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA dark pill track appears with a white circular handle on the left and the label "Slide to confirm payment".
  2. 2
    Drag the handlePress the handle and drag right — it follows your finger 1:1 and a green fill grows behind it.
  3. 3
    Release earlyLet go before the end — the handle and fill spring back to the start and nothing is confirmed.
  4. 4
    Slide all the wayDrag to the far right and release — the track locks green, the label becomes "✓ Payment confirmed", and a reset link appears.
  5. 5
    Reset and replayClick "↺ Reset" — everything animates back so you can try again or re-arm the control.
  6. 6
    Wire your actionPut your real API call or navigation inside complete() — it only runs on a full, intentional slide.

Real-world uses

Common Use Cases

Payment and checkout confirmation
A deliberate "slide to pay" before charging a card. Place it after an order summary so users review then commit.
Destructive action guards
Require a full slide to delete an account or wipe data; pair with a confirm dialog for an extra typed safeguard.
Dispatch and approval flows
"Slide to send", "slide to approve", or "slide to publish" in admin tools where an accidental tap would be costly. Pair reversible ones with a snackbar with undo.
Unlock and access controls
Slide-to-unlock for kiosks, lock screens, or gated content, mirroring the original mobile unlock gesture.
Emergency and high-stakes triggers
Arm or trigger an action that must not fire by accident, where the long deliberate motion is the safety mechanism.
Ride-share / delivery handoffs
"Slide to start trip" or "slide to mark delivered" — a confident, unambiguous commit gesture on mobile.

Got questions?

Frequently Asked Questions

Put your code inside complete() — it is called only when the handle is released at the end of the track. For async actions (a payment API), keep the locked state during the request and, on failure, call resetSlide() with an error message so the user can slide again; on success, leave it locked or navigate away.

Transforms (translateX, scaleX) run on the compositor for smoothness, and — crucially for this site's framework exports — Tailwind's transition utility animates transform but not raw width. Using scaleX for the fill means the snap-back animation works identically in the HTML, React, Vue, and Tailwind versions.

up() confirms when pos >= maxPos() - 4 (within 4px of the end). Lower the tolerance for a stricter "must reach the very end" feel, or raise it to forgive a slightly short slide. You can also require holding at the end briefly before committing by adding a short timer in up().

Dragging alone is not accessible, so provide a keyboard path: make the handle a focusable <button> (it is) and support Enter/Space or Arrow-Right-to-fill as an alternative that calls complete(). Add role="slider" with aria-valuenow updated as it moves, and ensure the confirmed state is announced via the label text, not colour alone.

In React, store the position in a ref (not state, to avoid re-render per frame), attach pointer listeners in a useEffect with cleanup, and set the transform via the handle ref; flip a confirmed state in complete. In Vue, use template refs and onMounted/onUnmounted. In Angular, bind in ngAfterViewInit with @ViewChild. The transform math and snap-back CSS port unchanged.