rn-swipe-button

react native swipe/slide button component

Usage no npm install needed!

<script type="module">
  import rnSwipeButton from 'https://cdn.skypack.dev/rn-swipe-button';
</script>

README

React Native Swipe Button Component


npm install rn-swipe-button --save

import SwipeButton from 'rn-swipe-button';

const renderSwipeButton = () => (<SwipeButton />)


Screenshots

iOS Android iOS GIF Android RTL

These screenshots are from demo app under examples folder in the repo


Component properties

    containerStyles: PropTypes.object,
    disabled: PropTypes.bool,
    disableResetOnTap: PropTypes.bool,
    disabledRailBackgroundColor: PropTypes.string,
    disabledThumbIconBackgroundColor: PropTypes.string,
    disabledThumbIconBorderColor: PropTypes.string,
    enableReverseSwipe: PropTypes.bool,
    forceReset: PropTypes.func,  // RNSwipeButton will call this function by passing a "reset" function as argument. Calling "reset" will reset the swipe thumb.
    height: PropTypes.oneOfType([
       PropTypes.string,
       PropTypes.number,
    ]),
    onSwipeFail: PropTypes.func,
    onSwipeStart: PropTypes.func,
    onSwipeSuccess: PropTypes.func,
    railBackgroundColor: PropTypes.string,
    railBorderColor: PropTypes.string,
    railFillBackgroundColor: PropTypes.string,
    railFillBorderColor: PropTypes.string,
    railStyles: PropTypes.object,
    resetAfterSuccessAnimDelay: PropTypes.number, // This is delay before resetting the button after successful swipe When shouldResetAfterSuccess = true 
    resetAfterSuccessAnimDuration: PropTypes.number,
    screenReaderEnabled: PropTypes.bool,
    shouldResetAfterSuccess: PropTypes.bool, // If set to true, buttun resets automatically after swipe success with default delay of 1000ms
    swipeSuccessThreshold: PropTypes.number, // Ex: 70. Swipping 70% will be considered as successful swipe
    thumbIconBackgroundColor: PropTypes.string,
    thumbIconBorderColor: PropTypes.string,
    thumbIconComponent: PropTypes.node, Pass any react component to replace swipable thumb icon
    thumbIconImageSource: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
    thumbIconStyles: PropTypes.object,
    thumbIconWidth: PropTypes.number,
    title: PropTypes.string,
    titleColor: PropTypes.string,
    titleFontSize: PropTypes.number,
    titleMaxFontScale: PropTypes.number, // Ex: 2. will limit font size increasing to 200% when user increases font size in device properties
    titleStyles: PropTypes.object,
    width: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),

Code for above screenshots

import React, {useState} from 'react';
import {SafeAreaView, View, Text, StatusBar, Button} from 'react-native';

import Icon from 'react-native-vector-icons/FontAwesome';

import thumbIcon from './assets/thumbIcon.png';
import arrowRight from './assets/arrow-right.png';
import styles from './styles';

import SwipeButton from 'rn-swipe-button';


const App: () => React$Node = () => {
  const [disableCBButton, setDisableCBButton] = useState(false)
  const defaultStatusMessage = 'swipe status appears here';
  const [swipeStatusMessage, setSwipeStatusMessage] = useState(
    defaultStatusMessage,
  );

  setInterval(() => setSwipeStatusMessage(defaultStatusMessage), 5000);
  const updateSwipeStatusMessage = (message) => setSwipeStatusMessage(message);
  const renderSubHeading = (heading) => (
    <Text style={styles.subHeading}>{heading}</Text>
  );
  let forceResetLastButton = null;

  const CheckoutButton = () => {
    return(
        <View style={{width: 100, height: 30, backgroundColor: '#C70039', borderRadius: 5, justifyContent: 'center', alignItems: 'center'}}>
            <Text style={{color: '#ffffff'}}>Checkout</Text>
        </View>
    );
  } 


  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <View style={styles.container}>
          <Text style={styles.title}>React Native Swipe Button</Text>
          <Text style={styles.swipeStatus}>{swipeStatusMessage}</Text>
          {renderSubHeading('Disabled')}
          <SwipeButton thumbIconImageSource={arrowRight} disabled />
          {renderSubHeading('Swipe status callbacks')}
          <SwipeButton
            containerStyles={{borderRadius: 5}}
            height={30}
            onSwipeFail={() => updateSwipeStatusMessage('Incomplete swipe!')}
            onSwipeStart={() => updateSwipeStatusMessage('Swipe started!')}
            onSwipeSuccess={() =>
              updateSwipeStatusMessage('Submitted successfully!')
            }
            railBackgroundColor="#31a57c"
            railStyles={{borderRadius: 5}}
            thumbIconComponent={CheckoutButton}
            thumbIconImageSource={arrowRight}
            thumbIconStyles={{borderRadius: 5}}
            thumbIconWidth={100} 
            title="Submit order"
          />
          {renderSubHeading('Reverse swipe enabled')}
          <SwipeButton
            enableReverseSwipe
            onSwipeSuccess={() => updateSwipeStatusMessage('Slide success!')}
            railBackgroundColor="#a493d6"
            thumbIconBackgroundColor="#FFFFFF"
            title="Slide to unlock"
          />
          {renderSubHeading('Set a component as thumb icon & use forceReset')}
          <SwipeButton
            disableResetOnTap
            forceReset={ reset => {
              forceResetLastButton = reset
            }}
            railBackgroundColor="#9fc7e8"  
            railStyles={{
              backgroundColor: '#44000088',
              borderColor: '#880000FF',
            }}
            thumbIconBackgroundColor="#FFFFFF"
            title="Slide to unlock"
          />
          <View style={{ alignItems: 'center', marginBottom: 5 }}>
            <Button onPress={() => forceResetLastButton && forceResetLastButton()} title="Force reset" />
          </View>  
          {renderSubHeading('Set .png image as thumb icon')}
          <SwipeButton thumbIconImageSource={thumbIcon} railBackgroundColor="#cfb0dd"/>
          {renderSubHeading('Set height & reset after successful swipe')}
          <SwipeButton height={25} shouldResetAfterSuccess={true} resetAfterSuccessAnimDelay={1000} />
          {renderSubHeading('Set height and width')}
          <View style={{ flexDirection: 'row', alignItems: 'center' }}>
            <SwipeButton height={35} width={200} title="Swipe" disabled={disableCBButton} />
            <View style={{ marginLeft: 15, width: 150, height: 32 }}><Button onPress={() => setDisableCBButton(!disableCBButton)} title="Toggle disable" /></View>
          </View>  
        </View>
      </SafeAreaView>
    </>
  );
};

Note

  • In accessibility mode this component works like a regular button (double tap to activate)
  • We are supporting RTL out of the box. For RTL layouts, swipe button works by default as right to left swipe.

Tech Stack

  • Node
  • Yarn
  • JavaScript
  • TypeScript
  • ReactNative

Running example app

  1. git clone https://github.com/UdaySravanK/RNSwipeButton.git
  2. cd RNSwipeButton/examples/RNSwipeButtonDemo
  3. yarn
  4. To run on an android emulator

    yarn android
    Make sure of
    • Android Studio is configured
    • Global paths set correctly for Android SDK i.e ANDROID_HOME, tools, platform-tools
    • Java8 is installed
    • At least one emulator is ready
  5. To run on an ios simulator

    yarn ios
    Make sure of
    • xcode is configured
    • cocoapods installed
    • If seeing issues then run pod deintegrate & pod install
    • If seeing issues with fonts
      1. Open ios workspace project in xcode
      2. Select RNSwipeButtonDemo
      3. Go to Build phases
      4. Open 'Copy Bundle Resources' and delete all .ttf files