Skip to content
Native Animation
Before After Compare animation preview

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

npx nativeanimation add before-after-compare
SkiaGlass

Before After Compare

A draggable photo comparison with a clipped reveal and configurable image, labels, 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 draggable photo comparison with a clipped reveal and configurable image, labels, fonts, and accent color.

How it works

  1. Skia renders one source image into two stationary layers, so dragging changes only the clipping boundary rather than sliding either photo.
  2. The untreated layer uses a cool, low-saturation color matrix; the edited layer derives a warm live grade from exposure, contrast, warmth, and saturation values.
  3. One continuous shared value drives the reveal mask, handle, and fading side labels. A projected release velocity feeds an interruptible spring.
  4. A second gesture updates the selected color adjustment entirely on the UI thread, while JavaScript receives only the final value.
  5. BlurView supplies the glass labels and 44-point handle, and copied Lucide paths keep every icon consistent.

Install

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

For Skia on web, follow the Expo/Skia CanvasKit setup used by your Expo SDK. Icons are from Lucide (ISC).

Usage

import { BeforeAfterCompare } from './before-after-compare';

export function Editor() {
  return <BeforeAfterCompare image={require('./portrait.jpg')} />;
}

With personality controls and imperative autoplay:

const editorRef = useRef<BeforeAfterCompareRef>(null);

<BeforeAfterCompare
  ref={editorRef}
  image={require('./portrait.jpg')}
  accentColor="#A78BFA"
  brandName="Northlight"
  initialPosition={0.62}
  onAdjustmentChange={(adjustment, value) => saveGrade(adjustment, value)}
/>;

Props

PropTypeDefaultDescription
imageDataSourceParamrequiredImage rendered in both comparison layers.
brandNamestring"Studio"Product name shown in the footer lockup.
titlestring"Edit"Center navigation title.
saveLabelstring"Save"Save action text and accessible label.
beforeLabelstring"Before"Untreated-side label.
afterLabelstring"After"Edited-side label.
accentColorstring"#A78BFA"Active control and glow color.
initialPositionnumber0.5Initial normalized reveal position.
initialAdjustmentBeforeAfterAdjustment"exposure"Initially selected adjustment.
fontFamilystringsystemBody and label font.
mediumFontFamilystringsystemEmphasized control font.
monoFontFamilystringsystemNumeric value font.
onBack() => void—Called when Back is pressed.
onSave() => void—Called when Save is pressed.
onPositionChange(position: number) => void—Called after direct position input settles.
onAdjustmentChange(adjustment, value) => void—Called when an adjustment drag ends.
accessibilityLabelstring"Before and after photo comparison"Screen-reader label for the reveal control.
styleStyleProp<ViewStyle>—Outer container style.
testIDstring—Test identifier.

The ref exposes playIntro(), setPosition(position), and resetAdjustments().

Why this one

Most before/after controls fake the comparison by translating two images. This version keeps both layers perfectly registered, adds velocity-aware edge rebound and double-tap endpoints, and turns the familiar divider into a polished photo-editing surface with live grading and accessible 10% steps.

Compatibility

  • Expo SDK 58, React Native 0.88, Reanimated 4.7, Worklets 0.13, and Skia 2.14.
  • iOS: supported.
  • Android: supported; the glass handle uses Expo Blur's SDK 31+ method.
  • Web: supported.
  • Expo Go: supported by the installed Expo modules in SDK 58.

Accessibility

The comparison is exposed as an adjustable control with increment and decrement actions in 10% steps. Before and After capsules are tappable endpoint alternatives, every hit target is at least 44 points, and reduced-motion mode removes spring rebound and autoplay movement.

Customization notes

Movement follows gestures, scroll position, or interruptible spring physics. A global duration is not exposed; reduced-motion fades retain their short fixed timing.