# Swipe to confirm

> Slide to confirm: the thumb follows the finger 1:1, the track fills behind it and the label fades, a tick marks the point of no return, and at the end the track gathers into a spinner and opens into the result.

- Type: Component (actions)
- Access: Free, open source (MIT)
- Page: https://goodui.dev/native/components/swipe-to-confirm
- Markdown: https://goodui.dev/native/components/swipe-to-confirm.md
- Registry item: https://goodui.dev/native/r/swipe-to-confirm.json
- Dependencies: react-native-gesture-handler, react-native-reanimated, react-native-svg
- Keywords: react native slide to confirm, swipe to pay, slide to unlock, swipe button, slide button expo, swipe to accept

## When to use

- Committing money or something hard to undo where a stray tap must not count: pay, send, place order.
- Starting something physical or time-bound: start a ride, check in, clock in, end a workout.
- Confirming at the bottom of a review screen, within thumb reach.

## When not to use

- Deleting or other destructive actions inside a list: use hold-to-confirm, which works in place without horizontal travel.
- Ordinary actions: use button; sliding for everything is tiring.
- Inside horizontally scrolling or swipeable containers (carousels, swipe-actions rows).

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add https://goodui.dev/native/r/swipe-to-confirm.json
npx expo install --fix
```

The component lands in `components/goodui-native/swipe-to-confirm/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs locale.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
import { SwipeToConfirm } from "@/components/goodui-native/swipe-to-confirm/swipe-to-confirm";

export function PayBar({ pay }: { pay: () => Promise<void> }) {
  return <SwipeToConfirm label="Slide to pay €24.00" confirmedLabel="Paid" onConfirm={pay} />;
}
```

## Examples

### Start a ride, success tone, stays confirmed

```tsx
<SwipeToConfirm tone="success" size="lg" label="Slide to start ride" confirmedLabel="Ride started" resetAfter={false} onConfirm={startRide} />
```

### A request that can fail

```tsx
<SwipeToConfirm label="Slide to send €1,240" errorLabel="Card declined" onConfirm={() => api.send(transfer)} />
```

## API reference

### SwipeToConfirm

`import { SwipeToConfirm } from "@/components/goodui-native/swipe-to-confirm/swipe-to-confirm";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` (required) | `string` | – | What sliding does, for example "Slide to pay €24.00". |
| `onConfirm` (required) | `() => unknown` | – | Runs when the thumb reaches the end. Return a promise: the track becomes a spinner until it settles. |
| `tone` | `"accent" \| "success" \| "danger"` | `"accent"` | `accent` for payments and sends, `success` for check-ins, `danger` for destructive actions. |
| `size` | `"md" \| "lg"` | `"md"` | 56 or 64 pt tall. |
| `confirmedLabel` | `string` | – | Shown with the check once confirmed, for example "Paid". |
| `errorLabel` | `string` | – | Shown when the promise rejects, before the thumb springs back. Long reasons wrap to two lines. Same as `labels.error`. |
| `icon` | `ReactNode \| ((color: string) => ReactNode)` | – | Thumb icon. Defaults to an arrow. A function receives the icon color. |
| `disabled` | `boolean` | `false` | Dims the control and ignores presses. |
| `resetAfter` | `number \| false` | `1800` | Return to the start this many ms after confirming. `false` keeps the confirmed state. |
| `accessibilityHint` | `string` | – | Read by screen readers after the label. Same as `labels.hint`. |
| `labels` | `Partial<SwipeToConfirmLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- The track is one button with the label; disabled and busy are in accessibilityState and the label follows the state (in progress, done, error).
- Screen readers cannot slide: the activate action (double tap) confirms directly. On the web, Enter or Space on the focused track does the same.
- Results are announced with AccessibilityInfo.announceForAccessibility.
- Default hint: 'Slide the handle to the end to confirm'.

## Motion

- Touch down: the thumb gives to 0.92 on the snappy spring before anything moves.
- Drag: the thumb tracks the finger 1:1 with a little rubber band before the start; the track's fill grows behind it and darkens from faint to solid; the label drifts along and fades by 60%.
- Release past 85% (or a flick that would reach the end from past halfway) snaps to the end with the finger's velocity; earlier, it springs back on smooth with the same velocity.
- Pending: the track gathers into a circle on the morph spring around a spinner. Result: it opens back on morph to green with a drawn check, or to red with the error label and a shake, then springs back.
- A tap on the track nudges the thumb forward and back on the bouncy spring to teach the gesture.
- Reduced motion: the thumb still follows the finger, but releases jump into place, the track never changes shape, there is no nudge or shake, and states crossfade.

## Haptics

- select when the thumb crosses the point of no return
- confirm when confirmed (after the promise resolves), error when it rejects

## Performance

- The drag runs entirely on the UI thread through Gesture Handler and Reanimated. React renders only on status changes.

## Notes for AI

- Return the promise from onConfirm; the component shows pending, success and error. Do not add a loading flag.
- errorLabel can carry the reason: it shows at subhead size and wraps to two lines inside the track (longer text ends in an ellipsis), so keep it under about 50 characters.
- It stretches to its parent's width. Place it in the bottom third of the screen with 16 pt gutters.
- Label starts with 'Slide to' and names the amount or outcome. confirmedLabel is the past tense: 'Paid', 'Sent', 'Checked in'.
- resetAfter={false} keeps the confirmed state, for flows that navigate away afterwards.
- Requires GestureHandlerRootView at the app root (see the foundation setup).

## Related

- [Hold to confirm](https://goodui.dev/native/components/hold-to-confirm.md): Confirms an irreversible action by holding: ink fills from the leading edge, the label inverts where the ink passes, and haptics tick at every quarter.
- [Button](https://goodui.dev/native/components/button.md): A press-responsive button with haptics that runs async actions on its own: it gathers into a spinner, then opens into a success or error state.
- [Bottom sheet](https://goodui.dev/native/components/bottom-sheet.md): A sheet that rests at detents, follows the finger 1:1, settles with velocity and hands drags off to its scroll view.

## Guidance for AI tools

Swipe to confirm: Slide to confirm: the thumb follows the finger 1:1, the track fills behind it and the label fades, a tick marks the point of no return, and at the end the track gathers into a spinner and opens into the result. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
