Sliding button
DraftSliding buttons are a variation of the standard primary button. By requiring a different gesture to confirm an action, they help reduce accidental taps and reinforce user intent.
- Usage
- Specs
- Content
- Status & changelog
- Code
Common alternative names
Swipe button, draggable button
Anatomy
A sliding button consists of a draggable handle with a predefined icon and a base track with a customisable label. All of the elements below are required.
(Required)
(Required)
(Required)
(Required)
Iconography
Sliding buttons use a single forward arrow icon to convey a clear interaction affordance and maintain consistency across experiences. The component does not support custom icons.
Usage
Use sliding buttons to let users take important actions. They should be used as the last step in a multi-step flow (like confirming a request or completing a transaction) or to introduce friction to confirm a user's intent and prevent accidental button taps (like initiating an emergency call).
Use cases
Sliding buttons introduce intentional friction in flows with a prominent primary action. The differentiated interaction pattern helps prevent accidental taps.
Users must take deliberate, intentional steps to confirm their intent before triggering a costly or non-reversible action like making a payment or initiating an emergency call.
Caution
If the action is not critical, a sliding button may be unnecessary and may add unnecessary complexity to the interface. Use a standard Button instead.
Mobile environments only
Using a swipe interaction as an action gesture feels natural in a mobile environment.
We discourage using sliding buttons in desktop environments. Trying to complete the task with a mouse or trackpad feels unnatural and is not a widely adopted pattern. Use a standard confirmation dialog or button on desktop.
Behavior
Users drag on the arrow affordance along the track. Once the arrow reaches a threshold, the sliding button's action is triggered.
States
| State | Description |
|---|---|
| Preloading | An interim state when the component content is loading. Uses a placeholder skeleton. |
| Enabled | Handle rests at the start of the track. Label is visible. The component is ready for interaction. |
| Focus | Text and icons use inverse primary. Container uses inverse primary. Outline: 3px focus border using borderAccent. |
| On drag | While the handle is being dragged, the label text transitions to a contentStateDisabled fill to indicate the action is in progress. |
| Loading | A spinner replaces the label and the arrow affordance is removed. Used after the threshold is reached while the action is being processed. |
| Disabled | Text and icons use contentStateDisabled. Container uses backgroundStateDisabled. The handle cannot be dragged. |
Slide affordance
The handle's arrow icon is the sole draggable element. On tap, the handle grows by 16px to provide a visual cue that the affordance has been engaged. The user then drags it across the track toward the trailing end.
Auto-complete thresholds
Users can slide the button to complete an action upon passing a threshold. Two threshold levels are provided to support different user types.
Demanding a high degree of interaction precision to complete an action proves difficult to users with physical and motor disabilities, as well as seniors. When choosing which threshold to use, think about who your users are and whether they would find it difficult to interact with the component in the "Hard" slide mode.
| Threshold | Value |
|---|---|
| Low (Easy) | Complete more than 20% |
| High (Hard) | Complete more than 80% |
Low threshold (Easy)
When the handle position exceeds 20% of the base width (slidingButton.x > 0.2 * base.width), the action auto-completes. Suitable for non-destructive confirmations where speed and accessibility matter.
High threshold (Hard)
When the handle position exceeds 80% of the base width (slidingButton.x > 0.8 * base.width), the action auto-completes. Use this for destructive or high-stakes actions where accidental confirmation must be minimised.
Haptics
(iOS)
| Event | Haptic pattern | Description |
|---|---|---|
| Failure | Failure (native) | On failure, play a Failure haptic pattern after resetting the state of the button. |
| On touch down | Single nudge | On touch down, play a single haptic nudge to confirm the affordance has been engaged. |
| Success | Success (native) | On success, play a Success haptic pattern to reinforce the request has been successfully submitted. |
Breakpoints
Sliding buttons should follow the same breakpoint rules defined in the Button documentation: full-width on mobile. This component is not recommended for desktop layouts.
Overrides
Color
Background colour customisations of the sliding button are supported but should stick to using primary, high-contrast colours like: InverseBackgroundPrimary, backgroundAccent, backgroundNegative, and backgroundPositive. Ensure your text and icon colours work on top of your chosen background. Ensure your custom background colour is tokenised so it flips in dark mode.
Distinguish the swipe affordance from the surrounding UI by using a primary, high-contrast background.
Don't invert the button styles or use secondary styling on the swipe affordance.
Size
Avoid resizing elements inside the button, like the icon or sliding button affordance. Try going up or down in size for the entire button instead.
Keep the sliding button height and the base button height the same.
Don't enlarge or shrink either part of the sliding button.
Examples
Related components
- Button: Standard rectangle button
- Button group: Group of related buttons
- Button dock: Fixed bottom container for primary actions
- Timed button: Auto-advancing countdown button
Metrics
| Property | Value |
|---|---|
| Track corner radius | Full-round (--radius-component-pill) |
| Track height | 52px |
| Track padding | 6px |
| Handle diameter | 40px |
| Handle corner radius | 50% (circle) |
| Minimum touch target | 48 × 48px |
Type and color
| Element | Token |
|---|---|
| Label text | label-large / --color-content-primary |
| Handle icon | --color-content-inverse-primary |
| Handle background (default) | --color-background-accent |
| Handle background (danger) | --color-background-negative |
| Track background (enabled) | --color-background-inverse-primary |
| Track background (disabled) | --color-background-state-disabled |
| Label text (disabled) | --color-content-state-disabled |
| Label text (on drag) | --color-content-state-disabled |
| Focus outline | 3px --color-border-accent |
Screen readers
VoiceOver
| Property | Value |
|---|---|
| Voiced preview | "Slide to [action], adjustable" |
| Label | Button label text |
| Role | Adjustable (slider) |
| Value | Percentage of track completed |
| Hint | "Swipe right to confirm" |
TalkBack
| Property | Value |
|---|---|
| Voiced preview | "Slide to [action], slider, [percentage]" |
| contentDescription | Button label text |
| Role | Slider (SeekBar) |
| Action | Swipe right to confirm |
Swipe versus Slide
Swipe
A swipe gesture occurs when the user moves one or more fingers across the screen in a specific horizontal or vertical direction. Swiping suggests a navigational gesture that helps users move between peer surfaces.
Slide
Using the word "slide" to indicate a gesture was first introduced in 2007 with the launch of the first iPhone. The gesture was specifically designed to avoid accidental triggers, for example, while the device is in your pocket.
Use the word "Slide" when you need an explicit affordance. This signifies the button needs an interaction trigger for the user to complete a given action or flow.
Don't use "Swipe". It carries meaning related to navigation rather than task completion.
Status & changelog coming soon.
Usage
SlidingButton presents a track with a draggable handle and a label. The user must drag the handle from one end to the other to trigger the onConfirm callback. If the user releases before reaching the threshold, the handle snaps back.
import { SlidingButton } from '@arch-ui/components';
<SlidingButton
label="Slide to confirm payment"
onConfirm={() => processPayment()}
/>
Variants
Default
A standard sliding track with a directional arrow handle and instructional label.
<SlidingButton label="Slide to submit" onConfirm={handleSubmit} />
Danger
Used for destructive actions. The track and handle use danger colour tokens to signal risk.
<SlidingButton
kind="danger"
label="Slide to delete account"
onConfirm={handleDelete}
/>
States
| State | Description |
|---|---|
| Idle | Handle rests at the start of the track. Label is visible. |
| Dragging | User is actively dragging the handle. The track may fill with a progress colour. |
| Confirmed | Handle has reached the end. The onConfirm callback fires and the button shows a success state. |
| Resetting | If the user releases early, the handle animates back to the start position. |
| Disabled | The handle cannot be dragged. The entire component appears muted. |
Expected props
Since this component is planned and not yet implemented, the following props represent the expected API.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | -- | Instructional text displayed on the track (e.g. "Slide to confirm"). |
onConfirm | () => void | -- | Called when the handle reaches the end of the track. |
kind | 'default' | 'danger' | 'default' | Visual style of the track and handle. |
disabled | boolean | false | Prevents interaction when true. |
threshold | number | 0.95 | Percentage of the track width the handle must cross to trigger confirmation (0 to 1). |
className | string | undefined | Additional CSS class names on the root element. |
Accessibility
- The handle should have
role="slider"witharia-valuemin,aria-valuemax, andaria-valuenowreflecting drag progress. - The label text should be associated with the handle via
aria-labeloraria-labelledby. - Keyboard support: users should be able to hold Arrow Right to move the handle and Enter to confirm when the threshold is met.
- When disabled,
aria-disabled="true"should be set on the handle.
Best practices
Do:
- Use for irreversible or high-stakes actions (payments, deletions, final confirmations).
- Provide clear, action-oriented label text that describes what will happen.
- Use the danger variant for destructive operations.
Don't:
- Do not use for routine actions -- a standard Button is sufficient.
- Do not set the threshold too low, as this defeats the purpose of requiring deliberate intent.
- Do not place more than one SlidingButton on the same screen.