npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@freefugga/react-smooth-swipe-button

v0.1.2

Published

Highly customizable smooth swipe button for React.

Readme

@freefugga/react-smooth-swipe-button

Highly customizable smooth swipe button for React web, created and maintained by Nishidh Jain (@freefugga).

Demo: https://smooth-swipe-demo.freefugga.workers.dev/

This package is meant for swipe-to-confirm actions in React web apps such as:

  • confirm checkout
  • approve destructive actions
  • accept terms or continue flows
  • acknowledge critical actions with intent

It keeps the drag path smooth by default with pointer events and direct DOM updates instead of depending on React re-rendering every frame.

Install

npm install @freefugga/react-smooth-swipe-button

Basic Usage

import { SwipeButton } from "@freefugga/react-smooth-swipe-button";

export function CheckoutAction() {
  return (
    <SwipeButton
      label="Slide to confirm payment"
      trackColor="#0f766e"
      onSwipeSuccess={() => {
        console.log("confirmed");
      }}
    />
  );
}

More Customization

import { SwipeButton } from "@freefugga/react-smooth-swipe-button";

export function DeleteAction() {
  return (
    <SwipeButton
      label="Swipe to delete"
      threshold={0.82}
      trackColor="#991b1b"
      thumbColor="#ffffff"
      trailColor="#fee2e2"
      labelColor="#ffffff"
      height={60}
      thumbSize={52}
      borderRadius={18}
      thumbRadius={16}
      completeBehavior="stay-complete"
      onSwipeSuccess={() => {
        console.log("deleted");
      }}
    />
  );
}

Threshold And Spring Control

import { SwipeButton } from "@freefugga/react-smooth-swipe-button";

export function CarefulDeleteAction() {
  return (
    <SwipeButton
      label="Swipe to delete"
      positiveOnProgress={0.9}
      spring={false}
      trackColor="#991b1b"
      onSwipeSuccess={() => {
        console.log("deleted");
      }}
    />
  );
}
  • positiveOnProgress={0.9} means the user must reach 90% before success.
  • spring={false} disables the bounce-back effect and uses a flat reset animation.

Timed Spring Example

import { SwipeButton } from "@freefugga/react-smooth-swipe-button";

export function TimedSpringAction() {
  return (
    <SwipeButton
      label="Swipe to continue"
      spring
      springMs={0.5}
      onSwipeSuccess={() => {
        console.log("continued");
      }}
    />
  );
}
  • springMs is in seconds, not milliseconds.
  • The bounce overshoot is capped internally to 80% of thumb width.

Live Progress Example

import { useState } from "react";
import { SwipeButton } from "@freefugga/react-smooth-swipe-button";

export function ProgressExample() {
  const [progress, setProgress] = useState(0);

  return (
    <SwipeButton
      label="Swipe to reserve seat"
      positiveOnProgress={0.75}
      onProgressChange={(value) => {
        setProgress(value);
      }}
      renderThumbContent={() => (
        <span>{Math.round(progress * 100)}%</span>
      )}
      onSwipeSuccess={() => {
        setProgress(0);
      }}
      onSwipeCancel={() => {
        setProgress(0);
      }}
    />
  );
}

Shared Props

These props are available on both the React and React Native packages.

| Prop | Type / values | Default | What it is for | | --- | --- | --- | --- | | label | string | "Swipe" | Main text shown on the rail | | disabled | boolean | false | Prevents dragging and dims the control | | loading | boolean | false | Replaces thumb content with a loader and disables swipe | | positiveOnProgress | number | 0.8 | Preferred success threshold; swipe progress must reach this value before success | | threshold | number | 0.8 | Legacy alias for the success threshold; use positiveOnProgress going forward | | spring | boolean | true | Enables the bounce-back spring reset animation | | springMs | number | 0.5 | Total bounce-reset time in seconds, capped from 0.1 to 0.5; try 0.5, 0.4, or 0.3 | | direction | "auto" \| "ltr" \| "rtl" | "auto" | Controls swipe direction; auto follows document direction | | completeBehavior | "reset" \| "stay-complete" | "reset" | Whether the thumb snaps back after success or stays complete | | disabledOpacity | number | 0.5 | Visual opacity when disabled | | height | number | 56 | Outer track height | | thumbSize | number | 48 | Width and height of the draggable thumb | | thumbMargin | number | 4 | Inner gap between thumb and rail edges | | borderRadius | number | 8 | Rail corner radius | | thumbRadius | number | 6 | Thumb and stretched trail corner radius | | trackColor | string | "#111827" | Rail background color | | thumbColor | string | "#ffffff" | Thumb background color | | trailColor | string | "#ffffff" | Color of the stretched thumb trail | | labelColor | string | "#ffffff" | Default label text color | | loaderColor | string | "#111827" | Default loader color | | animation | Partial<SwipeAnimationConfig> | built-in defaults | Motion tuning for complete and reset animations | | onSwipeStart | () => void | undefined | Called when drag starts | | onSwipeSuccess | () => void \| Promise<void> | undefined | Called after the swipe completes successfully | | onSwipeCancel | () => void | undefined | Called when the swipe ends before threshold | | onSwipeEnd | (result: "success" \| "cancel") => void | undefined | Called at the end of either success or cancel | | onProgressChange | (progress: number) => void | undefined | Reports current swipe progress from 0 to 1 |

React-only Props

| Prop | Type / values | Default | What it is for | | --- | --- | --- | --- | | className | string | undefined | CSS class for the outer track container | | style | React.CSSProperties | undefined | Inline style for the outer component | | trackStyle | React.CSSProperties | undefined | Inline style specifically for the track | | labelStyle | React.CSSProperties | undefined | Inline style for the label area | | thumbStyle | React.CSSProperties | undefined | Inline style for the draggable thumb | | trailStyle | React.CSSProperties | undefined | Inline style for the stretched trail | | labelClassName | string | undefined | CSS class for the label wrapper | | thumbClassName | string | undefined | CSS class for the thumb | | trailClassName | string | undefined | CSS class for the trail | | thumbContent | React.ReactNode | chevron | Replaces the default thumb icon | | loadingIndicator | React.ReactNode | spinner | Replaces the default loader UI | | successContent | React.ReactNode | undefined | Optional content shown after success | | renderLabel | (state) => React.ReactNode | undefined | Custom label renderer using live swipe state | | renderThumbContent | (state) => React.ReactNode | undefined | Custom thumb renderer using live swipe state | | ariaLabel | string | label | Accessibility label for the control |

Animation Config

animation accepts these optional keys:

| Key | Type | Default | What it controls | | --- | --- | --- | --- | | completeDuration | number | 100 | Duration of the final snap to success | | resetDelay | number | 0 | Delay before resetting after success | | resetDuration | number | 220 | Duration of the reset animation | | resetEasing | string | "cubic-bezier(0.22, 1, 0.36, 1)" | CSS easing used for reset | | springDamping | number | 15 | Legacy shared config value kept for API compatibility | | springStiffness | number | 120 | Legacy shared config value kept for API compatibility |

Render Callback State

renderLabel and renderThumbContent receive:

type SwipeButtonRenderState = {
  progress: number;
  thumbX: number;
  maxX: number;
  isDragging: boolean;
  isComplete: boolean;
  isLoading: boolean;
  isDisabled: boolean;
  isRTL: boolean;
};

Imperative Ref API

import { useRef } from "react";
import {
  SwipeButton,
  type SwipeButtonRef,
} from "@freefugga/react-smooth-swipe-button";

export function Example() {
  const ref = useRef<SwipeButtonRef>(null);

  return (
    <SwipeButton
      ref={ref}
      label="Swipe to continue"
      onSwipeSuccess={() => {
        console.log(ref.current?.getProgress());
      }}
    />
  );
}

Available methods:

  • reset()
  • complete()
  • getProgress()

Notes

  • Use @freefugga/react-native-smooth-swipe-button for React Native or Expo apps.
  • Use @freefugga/smooth-swipe-core only if you need the shared logic layer directly.
  • Live render callbacks are powerful, but they can add more JS work during drag than the default path.
  • positiveOnProgress is the clearer threshold prop for new integrations. threshold still works as a compatibility alias.
  • spring={true} is the default.
  • springMs={0.5} is the default bounce duration, and values are capped at 0.5.

License

MIT, copyright Nishidh Jain.