suiss/uim · Interaction

Card Stack

A deck of cards the user swipes left or right one at a time, with buttons, undo and an empty state.

Card Stack is an open-source mobile interaction from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Card Stack on iOS in light mode

CardStack shows the top card of data with up to visibleCount cards stacked behind it, each slightly smaller and lower. Dragging the top card sideways moves and tilts it, while the cards behind grow into place.

Releasing past threshold, or flicking faster than 800 points per second, flies the card off in that direction and shows the next one; otherwise it springs back. Use it for one-at-a-time decisions such as keep or skip.

Installation

$ pnpm dlx @esuiss/uim@latest add card-stack

The CLI also adds what it builds on: Button, Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-gesture-handler react-native-reanimated react-native-svg react-native-worklets
  1. Add the pieces it builds on: Button, Icon, Text, and the primitives components/primitives/haptics.tsx.

  2. Copy the source into components/interactions/card-stack.tsx:

uniwind/components/interactions/card-stack.tsx
import { cn } from "cn"
import {
  ArrowCounterClockwiseIcon,
  HeartIcon,
  XIcon,
} from "phosphor-react-native"
import * as React from "react"
import {
  type AccessibilityActionEvent,
  View,
  type ViewProps,
} from "react-native"
import { Gesture, GestureDetector } from "react-native-gesture-handler"
import {
  Easing,
  ReduceMotion,
  1. Update the import paths to match your project.

Usage

import { CardStack, CardStackEmpty, CardStackActions, CardStackSwipeButton, CardStackUndo } from "@/components/interactions/card-stack"
<Demo />

Pass data and renderItem, and handle onSwipe(direction, item, index). Add children below the deck: CardStackActions with CardStackSwipeButtons and a CardStackUndo, and a CardStackEmpty shown once every card is swiped.

Undo brings back the last card from the side it left and calls onUndo. useCardStack exposes index, count, remaining, canUndo, swipe and undo for custom controls. The CardStackDirection type is exported.

Examples

Mid swipe

A static frame of the top card dragged to the right.

iOS
Card Stack (mid swipe) on iOS in light mode

Empty

An empty deck showing CardStackEmpty.

iOS
Card Stack (empty) on iOS in light mode

Disabled

Turns off swiping and the buttons with disabled.

iOS
Card Stack (disabled) on iOS in light mode

API Reference

CardStack

The root that renders the deck and handles the drag gesture.

ExtendsViewProps
PropType
About
The items to show as cards.
Type
readonly T[]
Default
required
About
Renders one card from the item and its index.
Type
(item: T, index: number) => React.ReactNode
Default
required
About
Returns a key for a card. Defaults to its position.
Type
(item: T, index: number) => string
Default
—
About
Called with the direction, item and index after a card leaves.
Type
(direction: CardStackDirection, item: T, index: number) => void
Default
—
About
Called with the item and index after undo.
Type
(item: T, index: number) => void
Default
—
About
Drag distance that commits a swipe. Defaults to 120.
Type
number
Default
120
About
Cards stacked behind the top card. Defaults to 3.
Type
number
Default
3
About
Turns off the gesture and the swipe buttons.
Type
boolean
Default
false
About
Returns the label for the top card.
Type
(item: T, index: number) => string
Default
—
About
Classes for the deck area, which is h-96 by default.
Type
string
Default
—

CardStackEmpty

A dashed placeholder shown when no cards remain.

ExtendsViewPropsReact.RefAttributes<View>

CardStackActions

A centered row for the buttons.

ExtendsViewPropsReact.RefAttributes<View>

CardStackSwipeButton

A round button that swipes the top card left or right.

ExtendsReact.ComponentProps<typeof Button>
PropType
About
left shows an X icon, right shows a heart icon.
Type
CardStackDirection
Default
required

CardStackUndo

A button that restores the last swiped card.

ExtendsReact.ComponentProps<typeof Button>

Accessibility

  • The top card has Swipe left and Swipe right accessibility actions.
  • Cards behind the top card are hidden from screen readers.
  • Swipe buttons are labelled Swipe left and Swipe right, and undo is labelled Undo, unless you pass accessibilityLabel.

Notes

  • A medium impact haptic plays when a card is swiped by gesture, button or accessibility action, if the app provides an adapter through HapticsProvider.
  • Fly-out and spring animations respect the system reduce motion setting.
  • The left button icon uses text-danger; the right uses text-accent.