slide-accept
Slide-to-confirm interaction with drag handle, spring-back animation, keyboard support, and progressive enhancement.
Overview
The <slide-accept> component creates a slide-to-confirm interaction — a draggable handle that users slide across a track to confirm an action (like iOS “slide to power off”). If released early, the handle springs back. Once the threshold is reached, the component activates and fires a slide-accept:accept event.
<slide-accept label="Slide to confirm" activated-label="Confirmed!"> Slide to confirm</slide-accept>
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
label |
string | "Slide to confirm" |
Track label text displayed inside the track. |
activated-label |
string | "Confirmed!" |
Label shown after activation. |
attention |
string | — | Attention animation: "shimmer" or "pulse". |
threshold |
number | 90 |
Activation threshold as a percentage (0–100). |
Attention Animations
Shimmer
A sweeping shimmer effect draws attention to the track, encouraging interaction.
<slide-accept label="Slide to delete" activated-label="Deleted!" attention="shimmer"> Slide to delete</slide-accept>
Pulse
A pulsing glow on the handle draws attention to the draggable element.
<slide-accept label="Slide to send" activated-label="Sent!" attention="pulse"> Slide to send</slide-accept>
Custom Threshold
By default, the handle must reach 90% of the track to activate. Set threshold to a lower value to make activation easier.
<!-- Activate at 60% instead of default 90% --><slide-accept label="Slide halfway" threshold="60"> Slide halfway</slide-accept>
Keyboard Navigation
| Key | Action |
|---|---|
| ArrowRight | Move handle 5% |
| Shift + ArrowRight | Move handle 20% |
| ArrowLeft | Move handle back 5% |
| End | Activate immediately |
| Home | Reset to start |
Events
| Event | Description |
|---|---|
slide-accept:accept |
Fired when the handle reaches the activation threshold. |
slide-accept:reset |
Fired after reset() is called. |
const slider = document.querySelector('slide-accept'); slider.addEventListener('slide-accept:accept', () => { console.log('Confirmed!');}); slider.addEventListener('slide-accept:reset', () => { console.log('Reset');});
Public API
| Member | Type | Description |
|---|---|---|
.activated |
getter | Returns true if the component has been activated. |
.reset() |
method | Resets to initial state (handle at 0, label restored). |
const slider = document.querySelector('slide-accept'); // Check stateconsole.log(slider.activated); // true/false // Reset to initial stateslider.reset();
Accessibility
Slider Role
The handle has role="slider" with aria-valuemin, aria-valuemax, and aria-valuenow. Screen readers announce position changes as the handle moves.
Keyboard Support
The handle is focusable (tabindex="0") and responds to arrow keys. Shift + arrow provides larger steps for faster navigation. End activates immediately, Home resets.
Reduced Motion
Spring-back animation and attention effects are disabled when prefers-reduced-motion: reduce is active.
Styling
The track, handle, and label are all styleable with CSS. The handle is a .slide-handle button, and the track is a .slide-track div.
/* Custom handle color */slide-accept .slide-handle { background: oklch(55% 0.2 30);} /* Custom activated state */slide-accept[data-activated] .slide-handle { background: oklch(50% 0.15 145);}
Progressive Enhancement
Without JavaScript, the element renders its text content as a readable pill-shaped element. The :not(:defined) selector provides the fallback. Once JS registers the component, the track and drag handle take over.
/* Without JS: renders as pill-shaped inline element */slide-accept:not(:defined) { display: inline-flex; padding: var(--size-xs) var(--size-m); border-radius: var(--radius-pill); background: var(--color-surface-raised);}
Related
<compare-surface>— Before/after comparison slider<split-surface>— Resizable panel splitter