Skip to main content

Props

Static Props

Static properties are set during initialization and cannot be modified later.

container

  • Type: HTMLElement | SVGElement
  • Event listener container.
const observer = new Swipe({
container: document.getElementById('container'),
});

thumb

  • Type: HTMLElement | SVGElement | null
  • Default: null
  • An element that triggers swipe start.
    Movement is still calculated relative to the container — thumb only defines where a user can grab.
  • See demo
const observer = new Swipe({
container: document.getElementById('container'),
thumb: document.getElementById('thumb'),
});

buttons

  • Type: number[] | ((type: TPointersType) => number[])
  • Default: [0]
  • Determines which mouse buttons trigger events.
    • 0: Main button pressed, usually the left button or the un-initialized state
    • 1: Auxiliary button pressed, usually the wheel button or the middle button (if present)
    • 2: Secondary button pressed, usually the right button
    • 3: Fourth button, typically the Browser Back button
    • 4: Fifth button, typically the Browser Forward button
  • See MouseEvent.button.
  • See demo

Same shape as Pointers buttons.

const observer = new Swipe({
container: document.getElementById('container'),
buttons: [0], // left button click
buttons: [2], // right button click
buttons: [0, 2], // both buttons click
});

Different rules for mouse and touch:

const swipe = new Swipe({
container: document.getElementById('container'),
buttons: (type) => (type === 'touch' ? [0] : [2]),
});

pointers

  • Type: number | ((type: TPointersType) => number)

  • Default: 1

  • See demo

  • Required pointer count to activate swiping.
    Useful for touch gestures such as two-finger pan.
    If fewer pointers are present, swipe will not start.

    Same shape as Pointers minPointers.
    Swipe sets both minPointers and maxPointers on its internal Pointers instance to this value.

    During move, Swipe tracks the center between active pointers (from Pointers.move), not the first touch only.

const observer = new Swipe({
container: document.getElementById('container'),
pointers: 2, // swipe starts only with two fingers
});

One finger on mouse, two on touch:

const swipe = new Swipe({
container: document.getElementById('container'),
pointers: (type) => (type === 'mouse' ? 1 : 2),
});

Mutable Props

Mutable properties can be updated at runtime using .updateProps().

Adaptive props

To apply different values by viewport or device, use Responsive with this component as the source. Props will update automatically when breakpoints change.

enabled

  • Type: boolean
  • Default: true
  • Enables or disables swipe events.
const observer = new Swipe({
container: document.getElementById('container'),
enabled: false,
});

// change value
observer.updateProps({
enabled: true,
});

relative

  • Type: boolean
  • Default: false
  • Calculates coordinates relative to the container rather than the page.
  • See demo
const observer = new Swipe({
container: document.getElementById('container'),
relative: true,
});

// change value
observer.updateProps({
relative: false,
});

axis

  • Type: null | 'x' | 'y'
  • Default: null
  • Primary swiping axis.
  • See demo
const observer = new Swipe({
container: document.getElementById('container'),
axis: 'x',
});

// change value
observer.updateProps({
axis: 'y',
});

ratio

  • Type: number
  • Default: 1
  • Scales movement on x, y, and angle after swipe starts.
    Swipe activation still uses raw pointer distance, so threshold is not affected by ratio.
const observer = new Swipe({
container: document.getElementById('container'),
ratio: 1,
});

// change value
observer.updateProps({
ratio: 2,
});

grabCursor

  • Type: boolean
  • Default: false
  • Shows "grab" and "grabbing" cursors on thumb (if set) or container during interaction.
const observer = new Swipe({
container: document.getElementById('container'),
grabCursor: true,
});

// change value
observer.updateProps({
grabCursor: false,
});

willAbort

  • Type: (props: ISwipeCanMoveArg) => boolean
  • Default: () => false
  • Runs before swipe starts and determines whether the gesture should be blocked.
    Allows disabling swipe in specific UI states or when gesture conditions are not met.
const observer = new Swipe({
container: document.getElementById('container'),
willAbort: () => false,
});

// change value
observer.updateProps({
willAbort: ({ diff }) => diff.x > 5, // will prevent too fast swipe
});

threshold

  • Type: number
  • Default: 5
  • Minimum swipe distance (px) to trigger swipe start.
const observer = new Swipe({
container: document.getElementById('container'),
threshold: 5,
});

// change value
observer.updateProps({
threshold: 3,
});

minTime

  • Type: number
  • Default: 0
  • Minimum duration (ms) to trigger swipe move.
  • Means that user click the container, waits some time, and only then swipe is available.
const observer = new Swipe({
container: document.getElementById('container'),
minTime: 0,
});

// change value
observer.updateProps({
minTime: 0,
});

directionThreshold

  • Type: number
  • Default: 50
  • Minimum swipe distance (px) for directional callbacks.
  • Swipe supports direction detection (toTop, toBottom, toLeft, toRight).
  • To trigger a directional callback a user must swipe a certain amount of pixels - directionThreshold.
const observer = new Swipe({
container: document.getElementById('container'),
directionThreshold: 50,
});

// change value
observer.updateProps({
directionThreshold: 10,
});

preventEdgeSwipe

  • Type: boolean
  • Default: true
  • Prevents edge swiping (iOS swipe-back gesture).
const observer = new Swipe({
container: document.getElementById('container'),
preventEdgeSwipe: true,
});

// change value
observer.updateProps({
preventEdgeSwipe: false,
});

edgeSwipeThreshold

  • Type: number
  • Default: 20
  • Edge swipe threshold (px) from the left/right edge.
const observer = new Swipe({
container: document.getElementById('container'),
edgeSwipeThreshold: 20,
});

// change value
observer.updateProps({
edgeSwipeThreshold: 25,
});

preventTouchMove

  • Type: boolean
  • Default: true
  • Prevents touchmove from scrolling the page while swiping.
    Recommended to keep enabled for horizontal/vertical drags inside scrollable layouts.
const observer = new Swipe({
container: document.getElementById('container'),
preventTouchMove: true,
});

// change value
observer.updateProps({
preventTouchMove: false,
});

requireCtrlKey

  • Type: boolean
  • Default: false
  • Requires Ctrl key for swipe (mouse only).
const observer = new Swipe({
container: document.getElementById('container'),
requireCtrlKey: true,
});

// change value
observer.updateProps({
requireCtrlKey: false,
});

bounceDuration

  • Type: number
  • Default: 250
  • Duration (ms) of bounce-back when movement exceeds bounds, release inertia does not run, and canBounce allows it.
const swipe = new Swipe({
container: document.getElementById('container'),
bounds: () => ({ x: [0, 300] }),
bounceDuration: 250,
});

overflow

  • Type: () => number
  • Default: () => 50
  • Rubber-band distance past bounds (px for x/y, degrees for angle).
  • See demo
const swipe = new Swipe({
container: document.getElementById('container'),
bounds: () => ({ y: [0, 500] }),
overflow: () => 80,
});

bounds

  • Type: null | ((coords: ISwipeCoords) => ISwipeAxes | null)
  • Default: null
  • Movement limits per axis. Unset axis is unbounded. Values are normalized to [min, max].
  • The callback receives the full ISwipeCoords snapshot — use coords.scale, coords.movement, etc. when limits depend on zoom or layout.
  • Limits are re-read on every move update (including after setScale).
  • Use movement and scale in callbacks for transforms.
  • See demo
const swipe = new Swipe({
container: document.getElementById('wrapper'),
thumb: document.getElementById('thumb'),
relative: true,
bounds: ({ scale }) => ({
x: [0, wrapper.clientWidth - thumb.clientWidth * scale],
y: [0, wrapper.clientHeight - thumb.clientHeight * scale],
}),
onMove: ({ movement, scale }) => {
thumb.style.transform = `translate(${movement.x}px, ${movement.y}px) scale(${scale})`;
},
});

Static limits (callback may ignore coords):

const swipe = new Swipe({
container: document.getElementById('wrapper'),
relative: true,
bounds: () => ({ x: [0, 300], y: [0, 300] }),
onMove: ({ movement }) => {
thumb.style.transform = `translate(${movement.x}px, ${movement.y}px)`;
},
});

recalculateBoundsOnInertia

  • Type: boolean
  • Default: true
  • When true, bounds are re-read on every move update while release inertia is active.
    Set to false when bounds are static during inertia (for example in Snap) to avoid extra layout work.
const swipe = new Swipe({
container: document.getElementById('container'),
inertia: true,
bounds: () => ({ x: [0, 300] }),
recalculateBoundsOnInertia: false,
});

snap

  • Type: null | (() => ISwipeAxes | null)
  • Default: null
  • Snap targets per axis in movement space.
const swipe = new Swipe({
container: document.getElementById('container'),
relative: true,
snap: () => ({ angle: [0, 90, 180] }),
snapRadius: 15,
});

canBounce

  • Type: () => boolean
  • Default: () => true
  • When it returns false, overflow bounce-back on release is skipped (inertia may still run).
const swipe = new Swipe({
container: document.getElementById('container'),
bounds: () => ({ x: [0, 300] }),
canBounce: () => false,
});

// change value
swipe.updateProps({
canBounce: () => true,
});

snapRadius

  • Type: number | null
  • Default: null
  • Max distance to a snap target (same units as the axis). Falsy = no radius limit.
const swipe = new Swipe({
snap: () => ({ angle: [0, 90, 180] }),
snapRadius: 10,
});

inertia

  • Type: boolean
  • Default: false
  • Enables RAF-based release inertia after swipe end.
  • See demo
const swipe = new Swipe({
container: document.getElementById('container'),
inertia: true,
});

inertiaDecay

  • Type: number
  • Default: 0.05
  • Velocity decay per frame during inertia (higher = stops sooner).
  • See demo
const swipe = new Swipe({
inertia: true,
inertiaDecay: 0.05,
});

inertiaBounceEase

  • Type: number
  • Default: 0.3
  • Easing factor for pulling inertia back inside bounds (per frame, FPS-independent).
  • See demo
const swipe = new Swipe({
inertia: true,
bounds: () => ({ x: [0, 400] }),
inertiaBounceEase: 0.3,
});

inertiaRatio

  • Type: number
  • Default: 1
  • Extra multiplier for release velocity. Effective scale is ratio × inertiaRatio.
  • See demo
const swipe = new Swipe({
inertia: true,
inertiaRatio: 1.5,
});

inertiaDistanceModifier

  • Type: null | ((distance: ISwipeVec3) => ISwipeVec3 | null)
  • Default: null
  • Called once before release inertia starts with predicted inertia distance (x/y in px, angle in degrees).
    Return a vector to override the total inertia travel, or null to keep the default decay-based inertia.
  • See demo
const swipe = new Swipe({
inertia: true,
inertiaDistanceModifier: (distance) => ({
x: clamp(distance.x, -100, 100),
y: distance.y,
angle: 0,
}),
});

inertiaThreshold

  • Type: number
  • Default: 1
  • Minimum release speed to start inertia (px/s for x/y, deg/s for angle).
    Triggers inertiaFail when both linear and angular speed are below this value.
const swipe = new Swipe({
inertia: true,
inertiaThreshold: 1,
});

maxVelocity

  • Type: ISwipeVec3
  • Default: { x: 7, y: 7, angle: 3 }
  • Max release velocity per axis (coord/ms for x/y, deg/ms for angle).
    Falsy axis value disables inertia on that axis.
const swipe = new Swipe({
inertia: true,
maxVelocity: { x: 10, y: 10, angle: 5 },
});

Deprecated inertia props

caution

Timelined inertia (inertiaDuration, inertiaEasing) and velocityModifier are no longer applied. Use RAF inertia props above (inertiaDecay, inertiaBounceEase, inertiaThreshold, maxVelocity).