Skip to content
Native Animation
Thread Stack Timeline animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add thread-stack-timeline

Thread Stack Timeline

A conversation timeline with a swipeable summary stack and composer, with configurable threads, contact details, colors, and fonts.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

About this animation

A conversation timeline with a swipeable summary stack and composer, with configurable threads, contact details, colors, and fonts.

Why this one

A bubble list makes yesterday’s plans disappear into a long scroll. This stack keeps each conversation’s context visible, preserves your draft while browsing, and lands a sent message directly in the selected thread. Initials replace profile photos. A coral date rail and a rolling message count give the history its own identity.

How it works

  1. onLayout measures the host. Cards scale by 4% and move 10 points per previous level; tablet width stops at 560 points.
  2. One continuous shared position drives the stack, dates, scale, opacity, and paint order. A velocity projection selects the nearest thread; an interruptible spring with explicit mass and overshoot clamping settles it.
  3. Gesture Handler composes pan and tap exclusively. Tapping the active summary opens its message history; tapping outside, BACK, or Close thread closes it.
  4. Expansion uses one interruptible clock: the complete summary (including metadata and sent preview) fades and moves out over 180 ms before messages enter in chronological order, 50 ms apart. Closing reverses those phases, so the summary returns only after all messages disappear. Bubbles keep their measured rows with an 8-point gap. The history fills the card and scrolls with 16-point fades at both edges and padded endpoints.
  5. A real TextInput retains the draft while browsing. Sending dismisses the keyboard, flies a coral bubble into the selected card in 480 ms, appends a local message, rolls the count, and displays a check for 800 ms. onSend fires once after landing; persistence belongs to the host.
  6. Small containers and landscape use outer scrolling. Keyboard avoidance and a scroll-to-composer on keyboard appearance keep Send reachable. Reduced motion switches expansion immediately, with no flight, scaling, staggered displacement, or count rolling.

Install

npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler expo-linear-gradient @shopify/react-native-skia

Wrap the host in GestureHandlerRootView. On web, initialize CanvasKit before mounting this component using the Skia web setup for your Expo SDK. The component has no imports from the catalog or its demo. Icons: Lucide (ISC); see icons.ts and the kit’s license.

Usage

import { useRef } from 'react';
import { ThreadStackTimeline, type ThreadStackTimelineRef } from './thread-stack-timeline';

const timeline = useRef<ThreadStackTimelineRef>(null);

<ThreadStackTimeline
  ref={timeline}
  contact={{ name: 'Alex', initials: 'AL', color: '#FF7868' }}
  threads={[{
    id: 'weekend', date: '27 NOVEMBER',
    summary: 'Let’s choose a weekend for our trip.',
    messages: [{ id: 'hello', text: 'Does Saturday work?' }],
    files: 2, time: '2:40 PM',
  }]}
  onSend={(text, index) => saveMessage(text, index)}
/>;

// Optional controls and personality knobs:
timeline.current?.goTo(0);
timeline.current?.send('Saturday works!');

<ThreadStackTimeline
  contact={contact}
  threads={threads}
  sendDuration={420}
  placeholder="Write a reply"
  colors={{ accent: '#8FCDA8', outgoingText: '#102419' }}
  fontFamily="YourRegularFont"
  monoFontFamily="YourMonoFont"
/>;

Supply host safe-area padding, including the top inset. Font loading belongs to the host. The demo uses Geist regular, medium, light, and mono, loaded once by the app. For a light theme, override the complete palette (background, surface, text, muted, border, accent, button, buttonText, bubble, outgoingText).

Props

PropTypeDefaultPurpose
contactThreadContactRequiredName, initials, and avatar color
threadsTimelineThread[]RequiredStable unique IDs, date, summary, messages, files, time, optional messageCount
initialIndexnumber0Initial zero-based position
onSend(text, index) => void—Called after landing; host persists the message
onIndexChange(index) => void—Nearest index changes, not every frame
placeholder / sendLabelstringYour message / SendComposer copy
backLabel / onBackstring / () => voidBACK / —Back action, or close when expanded
previousLabel / nextLabel / closeLabelstringPrevious / Next / Close threadAccessible tap alternatives
messagesLabel / filesLabel / lastLabelstringMESSAGES / FILES / LASTMetadata copy
sentAnnouncementstringMessage sentScreen-reader success announcement
colorsPartial<ThreadStackColors>Dark paletteFull semantic color customization
fontFamily / mediumFontFamily / lightFontFamily / monoFontFamilystringSystemTypography roles
sendDurationnumber480Flight duration; minimum 180 ms
style / testIDStyleProp<ViewStyle> / string— / thread-stack-timelineIntegration and control IDs

Ref: goTo(index), send(text), expand(open), setDraft(text), and reset(). Empty or concurrent sends are ignored. reset() clears demo-local messages and replays the entrance. Messages stay local until the host saves them; avoid echoing a locally sent message back into the same thread while this instance remains mounted. Treat the supplied thread IDs and ordering as stable during a gesture.

Demo timing

Entrance 0–650 ms; previous thread at 600 ms; return at 1,100 ms; simulated typing 1,455–2,225 ms; send at 2,320 ms, landing at 2,800 ms; check lasts 800 ms; expand at 3,400 ms; close at 5,600 ms; reset at 7,600 ms. The first cycle starts after 100 ms. Typing updates the real input through the ref without opening the keyboard. Timers are canceled on unmount.

Compatibility

Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, Gesture Handler 3.3, Skia 2.14.0, and LinearGradient 58.0.3.

Accessibility

Thread targets expose summary and date, a button role, and an accessibility tap. Previous and Next provide 48-point tap alternatives to dragging. Send and Close have labeled targets, and landing announces the configurable success text. Reduced motion replaces navigation movement with fades, switches expansion immediately, and sends without flight. Body text remains scalable; long expanded histories and compact hosts can scroll. Test IDs suffix the root with -thread-N, -input, -send, -back, -previous, -next, and -close.