Skip to main content
SlideButton
@coinbase/cds-mobile@8.47.1
A button that slides to confirm an action.
import { SlideButton } from '@coinbase/cds-mobile/buttons/SlideButton'
Peer dependencies
  • react-native-gesture-handler: ^2.16.2
Related components

Basics

Use the onChange callback to update the checked state. This is the primary callback that controls both the visual and accessible state of the component.

Slide buttonSlide button
function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
/>
);
}

Variants

Use the variant prop to change the color of the button. The default variant is primary. Available variants are negative and positive.

Negative variant slide buttonNegative variant slide button
function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
variant="negative"
/>
);
}

Compact

Use the compact prop to reduce the height, border-radius and padding of the button:

function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
compact
/>
);
}

Disabled

Use the disabled prop to prevent interaction. This works for both unchecked and checked states.

function Example() {
return (
<VStack gap={2}>
<SlideButton
checked={false}
disabled
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
/>
<SlideButton checked disabled uncheckedLabel="Swipe to confirm" checkedLabel="Confirmed" />
</VStack>
);
}

Auto Complete on Threshold

By default, the user must release the handle past the threshold to complete. Set autoCompleteSlideOnThresholdMet to automatically complete as soon as the threshold is reached, without requiring release.

You can also adjust the threshold via checkThreshold (a value from 0 to 1, defaulting to 0.7).

function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
autoCompleteSlideOnThresholdMet
/>
);
}

Callback Lifecycle

SlideButton fires callbacks in a specific order during the slide gesture:

  1. onSlideStart -- when the gesture begins
  2. onChange -- when the slide completes past the threshold (sets checked to true)
  3. onSlideComplete -- immediately after onChange
  4. onSlideEnd -- always fires last

If the user releases before the threshold, onSlideCancel fires instead, followed by onSlideEnd.

Important: Always use onChange to manage the checked state. The checked prop drives the component's accessibilityLabel (switching between uncheckedLabel and checkedLabel), so failing to update it means screen readers won't announce the state change. Use onSlideComplete only for supplementary side effects (e.g. analytics, haptic feedback) that don't affect accessible state.

function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
onSlideStart={() => console.log('Started')}
onSlideComplete={() => console.log('Completed')}
onSlideCancel={() => console.log('Cancelled')}
onSlideEnd={() => console.log('Ended')}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
/>
);
}

Custom Nodes

Use startUncheckedNode and endCheckedNode to replace the default arrow icon and loading indicator on the handle.

Slide button with custom bell icons on the handleSlide button with custom bell icons on the handle
function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to enable notifications"
checkedLabel="Enabling..."
startUncheckedNode={<Icon color="fgInverse" name="bell" size="m" />}
endCheckedNode={<Icon color="fgInverse" name="bellCheck" size="m" />}
/>
);
}

Labels as Nodes

The uncheckedLabel and checkedLabel props accept ReactNode, so you can pass custom styled text or other components. When using non-string labels, the component uses accessibilityLabelledBy to associate the handle with the container element, so ensure your label nodes contain meaningful text content.

function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel={<Text font="label2">Swipe to confirm</Text>}
checkedLabel={
<Text color="fgInverse" font="label2">
Confirming...
</Text>
}
/>
);
}

Custom Background and Handle Components

You can fully customize the background and handle by providing your own components via SlideButtonBackgroundComponent and SlideButtonHandleComponent. Your components receive typed props (SlideButtonBackgroundProps and SlideButtonHandleProps) including a progress spring value and the current checked state.

Slide button with custom green/red background and handleSlide button with custom green/red background and handle
function Example() {
const [checked, setChecked] = useState(false);

const CustomHandle = ({ checked, ...props }: SlideButtonHandleProps) => (
<Pressable
{...props}
accessibilityLabel="Demo button"
accessibilityRole="button"
background={checked ? 'bgPositive' : 'bgNegative'}
borderRadius={300}
width="100%"
>
<HStack alignItems="center" height="100%" justifyContent="center" width="100%">
<HStack height="100%" pin="right" alignItems="center" padding={2}>
<Text font="label1">➡️</Text>
</HStack>
</HStack>
</Pressable>
);

const CustomBackground = ({ checked, ...props }: SlideButtonBackgroundProps) => (
<HStack
{...props}
bordered
alignItems="center"
background="bgSecondary"
borderColor={checked ? 'fgPositive' : 'fgNegative'}
borderRadius={300}
height="100%"
justifyContent="center"
width="100%"
>
<Text font="headline">Slide me</Text>
</HStack>
);

return (
<SlideButton
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
checked={checked}
onChange={setChecked}
SlideButtonBackgroundComponent={CustomBackground}
SlideButtonHandleComponent={CustomHandle}
height={50}
/>
);
}

Accessibility

SlideButton has built-in accessibility support. The component automatically derives its accessibilityLabel from the checked state -- displaying uncheckedLabel when unchecked and checkedLabel when checked. It also registers an activate accessibility action so screen readers can trigger the slide without performing a gesture.

Use onChange as your primary callback. The onChange callback updates the checked prop, which controls the accessible label. Placing critical logic in onSlideComplete without updating checked via onChange will leave the accessible state stale, meaning screen readers won't announce the confirmation.

When providing a custom SlideButtonHandleComponent, always spread the incoming props to preserve the built-in accessibilityActions and onAccessibilityAction handlers, and set accessibilityLabel and accessibilityRole="button" on the handle element.

When using ReactNode labels instead of strings, the component uses accessibilityLabelledBy to link to the container element, so ensure your custom label nodes contain meaningful text.

function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to send payment"
checkedLabel="Sending payment..."
/>
);
}

Is this page useful?

Coinbase Design is an open-source, adaptable system of guidelines, components, and tools that aid the best practices of user interface design for crypto products.