About this animation
A guide header that folds a photo hero and title into a toolbar, with configurable image, copy, fonts, and background color.
Why this one
Most collapsing headers treat the large heading and compact heading as two elements that crossfade, which creates a visible handoff. This component keeps one title alive throughout the transition, interpolating its position, size, color, and alignment from the same scroll value. It also adds a responsive overscroll crop, real materialized glass, and a complete two-screen travel guide instead of an isolated header sample.
How it works
onLayoutmeasures the component, so the hero, collapse distance, title endpoints, and spacing adapt inside phones, tablets, and sheets.- A Reanimated
Animated.ScrollViewwrites to onescrollYshared value; every visual state derives from that value without React updates per frame. - Negative scroll stretches the hero from its top edge, while positive scroll translates it at half speed and gently darkens it.
- The single title interpolates from the image into the center of the toolbar as the eyebrow and review line fade away.
- Near the threshold, an Expo Blur toolbar materializes, its hairline appears, and toolbar icons crossfade from white glass buttons to dark borderless controls.
- The forwarded ref can expand, collapse, or play the showcase sequence without introducing a second animation model.
Install
npx expo install expo-blur expo-image expo-linear-gradient @shopify/react-native-skia react-native-reanimated react-native-workletsUsage
import CollapsingLargeTitle from './CollapsingLargeTitle';
export function GuideScreen() {
return (
<CollapsingLargeTitle
heroImage={require('./assets/coast.jpg')}
title="Harbor Point"
stays={stays}
/>
);
}Customize its content, palette, fonts, and controls:
import { useRef } from 'react';
import CollapsingLargeTitle, {
type CollapsingLargeTitleRef,
} from './CollapsingLargeTitle';
export function IslandGuide() {
const guideRef = useRef<CollapsingLargeTitleRef>(null);
return (
<CollapsingLargeTitle
ref={guideRef}
heroImage={require('./assets/island.jpg')}
title="Lanterna Bay"
eyebrow="ISLAND GUIDE"
reviews="4.9 · 2,184 reviews"
facts={tripFacts}
stays={hotels}
tips={travelTips}
accentColor="#F5B544"
inkColor="#0F172A"
titleFontFamily="YourEditorialFont"
fontFamily="YourSansFont"
mediumFontFamily="YourMediumSansFont"
monoFontFamily="YourMonoFont"
onActionPress={openTripPlanner}
/>
);
}The forwarded ref exposes expand(animated?), collapse(animated?), and playShowcase().
Props
| Prop | Type | Default | Description |
|---|---|---|---|
heroImage | ImageSourcePropType | Required | Hero photograph. |
headerAccessory | ReactNode | — | Optional brand or context mark beside Back. |
title | string | 'Coastal guide' | Destination title that collapses into the toolbar. |
eyebrow | string | 'DESTINATION GUIDE' | Uppercase category over the hero. |
reviews | string | '4.9 · 1,240 reviews' | Review summary beside the star. |
description | string | Generic destination copy | Introductory guide paragraph. |
facts | CollapsingLargeTitleFact[] | Three trip facts | Compact travel data cards. |
stays | CollapsingLargeTitleStay[] | [] | Horizontal accommodation cards. |
tips | CollapsingLargeTitleTip[] | Four travel tips | Informational rows near the end. |
actionLabel | string | 'Plan this trip' | Fixed primary action label. |
priceLabel | string | 'from $1,240' | Price beside the action. |
backgroundColor | string | '#FBFAF7' | Warm content surface. |
inkColor | string | '#0F172A' | Toolbar, icon, and action color. |
accentColor | string | '#F5B544' | Accent for the star and editorial rule. |
fontFamily | string | System font | Body and supporting copy. |
mediumFontFamily | string | System font | Labels, controls, and headings. |
titleFontFamily | string | System font | Editorial title and display copy. |
monoFontFamily | string | System font | Facts and prices. |
onBack | () => void | — | Called when Back is pressed. |
onFavorite | () => void | — | Called when Favorite is pressed. |
onShare | () => void | — | Called when Share is pressed. |
onActionPress | () => void | — | Called when the fixed primary action is pressed. |
style | StyleProp<ViewStyle> | — | Outer-container style. |
testID | string | — | Test identifier for the outer container. |
Compatibility
- Expo SDK 58
- React Native 0.88
- Reanimated 4.7
- Skia 2.14
- iOS: supported
- Android: supported; blur uses the SDK 31+ method and a translucent fallback below it
- Web: supported
- Works in Expo Go because all native dependencies are included in this project's Expo SDK runtime
Accessibility
Back, Favorite, Share, and the primary action expose 44-point-or-larger labeled button targets with immediate press feedback. The guide uses a real scroll view for screen-reader navigation. With Reduce Motion enabled, hero scaling and parallax stop, the title switches without spatial interpolation, and the toolbar changes with a restrained fade.
Customization notes
The title follows scroll position, rather than a playback clock.




