About this animation
A boarding pass with a tear-away stub and falling paper feedback, with configurable passenger details, flight data, accent color, and fonts.
Why this one
Most tear-off ticket patterns stop at a flat translation. This version gives the interaction a credible product setting, an interruptible projected release, two matching torn edges, a gently rotating fall into a clear lower-left resting place, and a compact celebration that stays centered beneath the pass.
How it works
- The component measures its own container and scales the pass for both compact phones and taller screens.
- One continuous
progressshared value drives the stub position, rotation, perforation, pass recentering, route accent, and success reveal. - The vertical pan applies elastic resistance outside its bounds and projects release velocity before choosing whether to reattach or tear away.
- A spring carries the stub downward while the upper pass settles in the opposite direction, exposing matching rows of paper teeth.
- A spring introduces the green confirmation circle before one continuous Lucide check path draws with rounded ends.
- The button and forwarded ref use the same state transition as the gesture, so every input path stays synchronized.
Install
npx expo install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-workletsOn web, copy node_modules/canvaskit-wasm/bin/full/canvaskit.wasm into the web public directory. The included web entry waits for CanvasKit before it imports the Skia confirmation icon.
Usage
import TearOffBoardingPass from './TearOffBoardingPass';
export function TripScreen() {
return <TearOffBoardingPass originCode="MAD" destinationCode="JFK" seat="12A" />;
}Customize the content, palette, typography, and completion callback:
import { useRef } from 'react';
import TearOffBoardingPass, { type TearOffBoardingPassRef } from './TearOffBoardingPass';
export function TripScreen() {
const passRef = useRef<TearOffBoardingPassRef>(null);
return (
<TearOffBoardingPass
ref={passRef}
airlineName="Northwind"
passengerName="Avery Morgan"
flightDate="NOV 08"
boardingTime="6:20 AM"
flightNumber="NW 214"
gate="C07"
seat="8F"
accentColor="#FF5A4E"
colorScheme="dark"
fontFamily="YourSansFont"
displayFontFamily="YourDisplayFont"
monoFontFamily="YourMonoFont"
onTear={() => confirmBoarding()}
/>
);
}The forwarded ref exposes tear() and reset().
Props
| Prop | Type | Default | Description |
|---|---|---|---|
airlineName | string | 'Your airline' | Airline name displayed at the top of the pass. |
screenTitle | string | 'Ready for takeoff' | Product-screen heading above the pass. |
originCode | string | 'MAD' | Origin airport code. |
originCity | string | 'Madrid' | Origin city label. |
destinationCode | string | 'JFK' | Destination airport code. |
destinationCity | string | 'New York' | Destination city label. |
passengerName | string | 'Avery Morgan' | Passenger name. |
flightDate | string | 'OCT 24' | Flight date in the format used by the product. |
boardingTime | string | '7:35 PM' | Boarding time. |
flightNumber | string | 'NA 051' | Flight identifier. |
gate | string | 'B18' | Gate label. |
seat | string | '12A' | Seat label. |
tearLabel | string | 'Tear' | Label for the tear action. |
statusLabel | string | 'On time' | Flight status shown in the pass header. |
pullLabel | string | 'Pull down' | Drag instruction shown on the stub. |
successMessage | string | 'Have a great flight' | Message revealed after the stub separates. |
successDetail | string | 'Your gate is ready when you are.' | Supporting copy under the success message. |
accentColor | string | undefined | Accent used for the route, action, and celebration. |
colorScheme | 'light' | 'dark' | 'auto' | 'auto' | Light, dark, or system-selected presentation. |
fontFamily | string | undefined | Font family for interface text. |
displayFontFamily | string | undefined | Font family for route codes and prominent labels. |
monoFontFamily | string | undefined | Font family for changing or tabular travel data. |
accessibilityLabel | string | 'Boarding pass stub. Swipe down or activate to tear it off.' | Accessible label for the draggable ticket stub. |
onTear | () => void | undefined | Called when the tear-off animation settles. |
style | StyleProp<ViewStyle> | undefined | Optional style for the outer container. |
testID | string | undefined | Test identifier applied to the outer container. |
duration | number | 360 | Confirmation icon reveal duration in milliseconds, after the tear delay. Spring physics and reduced-motion timing are unchanged. |
Compatibility
- Expo SDK 58
- React Native 0.88
- Reanimated 4.7 and Worklets 0.13
- Skia 2.14
- iOS: supported
- Android: supported
- Web: supported
- Works in Expo Go because its native dependencies are included in the SDK
- Icons: Lucide (ISC)
Accessibility
The stub is an adjustable control with activate, increment, and decrement actions, and the 48-point Tear button provides a direct touch alternative. With reduced motion enabled, the component switches states immediately: it removes the spring, fall, rotation, and particle movement while preserving the success message and torn state.




