Skip to content
Native Animation
Link Unfurl Card animation preview

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

npx nativeanimation add link-unfurl-card
Loading

Link Unfurl Card

A link preview that unfolds from a note into a shared-image reader, with configurable image, preview copy, fonts, and accent color.

$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 link preview that unfolds from a note into a shared-image reader, with configurable image, preview copy, fonts, and accent color.

Why this one

The loading state has a visible rhythm: an underline draws, a spring opens the skeleton, a genuinely blurred photo resolves, the headline types, and metadata fades in. The same photo and card surface expand into a reader. Swipe dismissal preserves the URL as ordinary text; a labeled button offers the same action.

How it works

  1. Paste an HTTP(S) URL into the multiline note, or call ref.paste(url).
  2. Local URL validation selects the ready or error result. This component presents supplied preview data; it does not fetch or scrape URLs.
  3. A UI-thread loading progress drives the photo, headline characters, metadata, and skeleton. Separate shared values hold interruptible reveal, reader, drag, and press positions.
  4. A pan projects release velocity to either return the card or dismiss it. Gesture Handler composes tap and pan; there is no nested Pressable competing with the preview gesture.
  5. Reader expansion changes the geometry of the existing image and card, rather than mounting a replacement image.
  6. Semantic transitions notify onStateChange and assistive technology. The demo owns its cancellable autoplay timers.

Install

npx expo install expo-image expo-linear-gradient react-native-gesture-handler react-native-reanimated react-native-worklets

SDK-compatible versions used here: expo-image ~58.0.17, expo-linear-gradient ~58.0.3, Gesture Handler ~3.3.0, Reanimated 4.7.1, worklets 0.13.0. Wrap your app in GestureHandlerRootView. Copy the component, icons.ts, and index.ts into your app. No Skia initialization is needed. Icons: Lucide (ISC); paths are copied from the project kit and rendered as SVG image sources.

Usage

import { useRef } from 'react';
import { Button, View } from 'react-native';
import { LinkUnfurlCard, type LinkUnfurlCardRef } from './link-unfurl-card';

export function Note() {
  const preview = useRef<LinkUnfurlCardRef>(null);
  return (
    <View style={{ flex: 1, padding: 24 }}>
      <LinkUnfurlCard
        ref={preview}
        image={require('./assets/forest.jpg')}
        title="A quieter afternoon"
        summary="Take the longer path. Notice the light between the trees."
      />
      <Button title="Insert link" onPress={() => preview.current?.paste('https://journal.example/quiet')} />
    </View>
  );
}

Personality knobs:

<LinkUnfurlCard
  image={require('./assets/forest.jpg')}
  accentColor="#0EA5E9"
  loadDuration={1000}
  springDamping={30}
  colorScheme="light"
  fontFamily="YourInterfaceFont"
  titleFontFamily="YourEditorialFont"
  onStateChange={(state) => savePreviewState(state)}
/>

Props

PropTypeDefaultPurpose
imageImageSourcePropTypeRequiredSupplied preview photo
titlestringA moment worth savingPreview and reader headline
summarystringGeneric short summaryScrollable reader body
readingTimestring5 min readMetadata label
noteTitlestringNew noteNote heading
initialNotestringEmptyInitial editable note
fontFamilystringSystemUI typeface
titleFontFamilystringSystemEditorial typeface
accentColorstring#0EA5E9Link and action accent
loadDurationnumber1200Loading timeline in ms, minimum 400
springDampingnumber28Reveal and reader damping
colorSchemelight / dark / autoautoSurface theme
onStateChange(state) => void—JS-thread semantic transition callback
onInteraction() => void—Touch/edit signal for stopping autoplay
accessibilityLabelstringOpen link preview in readerPreview action label
styleStyleProp<ViewStyle>—Root container style
testIDstring—Root identifier

The ref exposes paste(url), expand(), close(), dismiss(), and reset(). States: idle, loading, ready, reader, dismissed, error. Dismiss keeps the URL; reset clears it. initialNote initializes the editor and supplies the reset value.

Compatibility

Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, worklets 0.13.0. Uses modules already present in this project's Expo Go environment. iOS, Android, and web are targeted. No new dependencies or native configuration changes.

Recommended allocated component height: at least 470 pt, with a width of at least 272 pt. The demo provides this space at 320×694 and 390×844. Reader content scrolls instead of shrinking type.

Accessibility

Interactive controls are labeled and at least 44 pt. The preview supports activate/dismiss accessibility actions, with explicit Read story, Dismiss, and Back to note controls outside the gesture surface. State changes are announced and the footer is a polite live region. Headline characters expose one complete accessible title. Reduced motion uses 200 ms fades, removes blur, shimmer, shake, drag flight, press scaling, and spatial interpolation; the explicit dismissal button remains available.

Demo timeline

At 350 ms the URL is inserted; the preview resolves by 1550 ms. At 2700 ms the same card expands. At 5250 ms it returns; at 6500 ms it is dismissed. The sequence restarts at 8050 ms. A touch or edit cancels autoplay immediately. Paste link, Invalid link, and Replay are bottom controls; the upper-right viewer-close area stays empty.