Skip to content
Sensors

useSwipe

Reactive swipe detection based on TouchEvents. Detects swipe direction and length.

useSwipe

Detect touch swipe gestures using TouchEvents.

LengthX
0px
LengthY
0px
Direction: none
Idle
swipe here (touch device)
import {
const useSwipe: (target: MaybeEventTarget, options?: DeepMaybeObservable<UseSwipeOptions>) => UseSwipeReturn
useSwipe
} from "@usels/web";
import {
const useRef$: {
<T = any>(initialValue: null): Ref$<T | null>;
<T = any>(initialValue: T): Ref$<T>;
<T = any>(): Ref$<T | null>;
}
useRef$
} from "@usels/core";
function
function SwipeDemo(): JSX.Element
SwipeDemo
() {
const
const el$: Ref$<HTMLDivElement | null>
el$
=
useRef$<HTMLDivElement>(): Ref$<HTMLDivElement | null> (+2 overloads)

Core (framework-agnostic) version of useRef$. Creates an observable element ref with opaque wrapping.

  • non-null value → Ref$<T>: current, get(), peek() return T
  • null / no arg → Ref$<T | null>: current, get(), peek() return T | null

Nullability is expressed via the type parameter, mirroring T | null at the call site.

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
const {
const isSwiping$: ReadonlyObservable<boolean>

Whether swiping is in progress

isSwiping$
,
const direction$: ReadonlyObservable<UseSwipeDirection>

Swipe direction

direction$
,
const lengthX$: ReadonlyObservable<number>

Horizontal swipe length (startX - currentX)

lengthX$
,
const lengthY$: ReadonlyObservable<number>

Vertical swipe length (startY - currentY)

lengthY$
} =
function useSwipe(target: MaybeEventTarget, options?: DeepMaybeObservable<UseSwipeOptions>): UseSwipeReturn

Framework-agnostic reactive swipe detector based on TouchEvents.

Listens to touchstart / touchmove / touchend on the target and tracks swipe direction, length, and start/end coordinates. threshold and callback fields are read reactively via opts$, so they may be swapped at runtime. passive is consumed once at mount — AddEventListenerOptions cannot change after the listener is registered.

useSwipe
(
const el$: Ref$<HTMLDivElement | null>
el$
, {
threshold: number
threshold
: 50,
onSwipeEnd: (e: any, dir: any) => any
onSwipeEnd
: (
e: any
e
,
dir: any
dir
) =>
any
console
.
any
log
(`Swiped ${
dir: any
dir
}`),
});
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
RefAttributes<HTMLDivElement>.ref?: Ref<HTMLDivElement> | undefined

Allows getting a ref to the component instance. Once the component unmounts, React will set ref.current to null (or call the ref with null if you passed a callback ref).

ref
={
const el$: Ref$<HTMLDivElement | null>
el$
}
HTMLAttributes<HTMLDivElement>.style?: CSSProperties | undefined
style
={{
StandardLonghandProperties<string | number, string & {}>.width?: Property.Width<string | number> | undefined

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Syntax: auto | <length-percentage [0,∞]> | min-content | max-content | fit-content | fit-content(<length-percentage [0,∞]>) | <calc-size()> | <anchor-size()>

Initial value: auto

| Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | 1 | 1 | 1 | 12 | 4 |

width
: 300,
StandardLonghandProperties<string | number, string & {}>.height?: Property.Height<string | number> | undefined

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Syntax: auto | <length-percentage [0,∞]> | min-content | max-content | fit-content | fit-content(<length-percentage [0,∞]>) | <calc-size()> | <anchor-size()>

Initial value: auto

| Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | 1 | 1 | 1 | 12 | 4 |

height
: 300,
StandardShorthandProperties<string | number, string & {}>.background?: Property.Background<string | number> | undefined

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Syntax: <bg-layer>#? , <final-bg-layer>

| Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | 1 | 1 | 1 | 12 | 4 |

background
: "#eee" }}>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Swiping: {
const isSwiping$: ReadonlyObservable<boolean>

Whether swiping is in progress

isSwiping$
.
ImmutableObservableBase<boolean>.get(trackingType?: TrackingType | GetOptions): {}
get
() ? "yes" : "no"}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Direction: {
const direction$: ReadonlyObservable<UseSwipeDirection>

Swipe direction

direction$
.
ImmutableObservableBase<UseSwipeDirection>.get(trackingType?: TrackingType | GetOptions): {}
get
()}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
Length: {
const lengthX$: ReadonlyObservable<number>

Horizontal swipe length (startX - currentX)

lengthX$
.
ImmutableObservableBase<number>.get(trackingType?: TrackingType | GetOptions): {}
get
()}, {
const lengthY$: ReadonlyObservable<number>

Vertical swipe length (startY - currentY)

lengthY$
.
ImmutableObservableBase<number>.get(trackingType?: TrackingType | GetOptions): {}
get
()}
</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}
import { observable } from "@usels/core";
const threshold$ = observable(50);
const { direction$ } = useSwipe(el$, { threshold: threshold$ });
// Later: adjust threshold reactively
threshold$.set(100);
ParameterTypeDescription
targetMaybeEventTarget-
optionsUseSwipeOptions (optional)-
OptionTypeDefaultDescription
thresholdnumber-Minimum distance in px to trigger swipe. Default: 50
onSwipeStart((e: TouchEvent) => void)-Callback on swipe start
onSwipe((e: TouchEvent) => void)-Callback on swipe move
onSwipeEnd((e: TouchEvent, direction: UseSwipeDirection) => void)-Callback on swipe end
passiveboolean-Use passive event listeners. Default: true

UseSwipeReturn

NameTypeDescription
isSwiping$ReadonlyObservable<boolean>Whether swiping is in progress
direction$ReadonlyObservable<UseSwipeDirection>Swipe direction
lengthX$ReadonlyObservable<number>Horizontal swipe length (startX - currentX)
lengthY$ReadonlyObservable<number>Vertical swipe length (startY - currentY)
coordsStart$ReadonlyObservable<{ x: number; y: number; }>Touch start coordinates
coordsEnd$ReadonlyObservable<{ x: number; y: number; }>Current/end touch coordinates
stop() => voidStop listening

View on GitHub