Lynx/Modules/Gestures/Swipeable
@sigx/lynx-gestures · Stable · Component library

Swipeable#

A horizontal swipe-to-reveal container built on Gesture.Pan().axis('x'). The pan tracking and foreground transform run on Lynx's main thread, so the row stays locked to the frame rate; on release it snaps to closed, open-left or open-right and emits swipeOpen / swipeClose to the background thread.

Import#

TSX
import { Swipeable } from '@sigx/lynx-gestures';

Basic usage#

The row content goes in the default slot. The reveal panels are render-prop functions passed to leftActions / rightActions — supply only the side(s) you want. On release the foreground snaps open once the drag passes snapThreshold, otherwise it springs back closed.

TSX
import { Swipeable } from '@sigx/lynx-gestures';

function InboxRow() {
    return (
        <Swipeable
            rightActionsWidth={100}
            snapThreshold={60}
            rightActions={() => (
                <view style={{ backgroundColor: 'crimson', justifyContent: 'center' }}>
                    <text style={{ color: 'white' }}>Delete</text>
                </view>
            )}
            onSwipeOpen={(e) => console.log('opened', e.side)}
            onSwipeClose={() => console.log('closed')}
        >
            <view style={{ padding: '16px' }}>
                <text>Swipe me left</text>
            </view>
        </Swipeable>
    );
}

The swipeOpen payload's side is 'left' or 'right' (a SwipeSide).

Actions on both sides#

Provide both leftActions and rightActions to reveal a panel in either direction, and size each independently with leftActionsWidth / rightActionsWidth. snapDuration controls how long the snap animation takes, and foregroundStyle styles the sliding foreground layer.

TSX
import { Swipeable } from '@sigx/lynx-gestures';

function MessageRow() {
    return (
        <Swipeable
            leftActionsWidth={120}
            rightActionsWidth={100}
            snapThreshold={60}
            snapDuration={200}
            foregroundStyle={{ backgroundColor: 'white' }}
            leftActions={() => (
                <view style={{ backgroundColor: 'seagreen', justifyContent: 'center' }}>
                    <text style={{ color: 'white' }}>Archive</text>
                </view>
            )}
            rightActions={() => (
                <view style={{ backgroundColor: 'crimson', justifyContent: 'center' }}>
                    <text style={{ color: 'white' }}>Delete</text>
                </view>
            )}
            onSwipeOpen={(e) => console.log('opened toward', e.side)}
        >
            <view style={{ padding: '16px' }}>
                <text>Swipe either way</text>
            </view>
        </Swipeable>
    );
}

Coordinating with a scrolling list#

Inside a list, wrap the rows in ScrollView from the same package. It provides a ScrollContext that descendant Swipeables read automatically — they yield the native scroll while a horizontal swipe is in progress, so vertical scrolling and swipe-to-reveal don't fight each other. No extra wiring is required.

TSX
import { ScrollView, Swipeable } from '@sigx/lynx-gestures';

function Inbox({ rows }: { rows: string[] }) {
    return (
        <ScrollView>
            {rows.map((label) => (
                <Swipeable
                    rightActionsWidth={100}
                    rightActions={() => (
                        <view style={{ backgroundColor: 'crimson', justifyContent: 'center' }}>
                            <text style={{ color: 'white' }}>Delete</text>
                        </view>
                    )}
                >
                    <view style={{ padding: '16px' }}>
                        <text>{label}</text>
                    </view>
                </Swipeable>
            ))}
        </ScrollView>
    );
}

Keep the foreground style / foregroundStyle structurally stable across renders — a background SET_STYLE on the swiped element can clobber the main-thread transform writes.

Props#

PropTypeDescription
leftActionsWidthnumberWidth in CSS pixels of the left reveal panel. Default 100.
rightActionsWidthnumberWidth in CSS pixels of the right reveal panel. Default 100.
snapThresholdnumberDrag distance past which the row snaps open on release rather than closed. Default 60.
snapDurationnumberDuration in ms of the snap animation. Default 200.
leftActions() => unknownRender-prop for the panel revealed when swiping right. Omit to disable the left side.
rightActions() => unknownRender-prop for the panel revealed when swiping left. Omit to disable the right side.
foregroundStyleRecord<string, string | number>Inline style applied to the sliding foreground layer.
classstringExtra CSS classes on the container.
styleRecord<string, string | number>Inline style on the container.

Slots#

SlotDescription
defaultThe row's foreground content that slides to reveal the action panels.

Events#

EventTypeDescription
onSwipeOpen(e: { side: SwipeSide }) => voidFired when the row snaps open. side is 'left' or 'right'.
onSwipeClose() => voidFired when the row snaps back closed.

See also#

  • Draggable — free-axis dragging built on Gesture.Pan().
  • API referenceSwipeableProps, SwipeSide and every other export, typed.