Building a Smooth Collapsible Header with Sticky Tabs in React Native
A step-by-step guide to building smooth, production-ready scroll interactions using Reanimated
Building a Smooth Collapsible Header with Sticky Tabs in React Native
A step-by-step guide to building smooth, production-ready scroll interactions using Reanimated

Most apps today (finance, social, dashboards) have one common UX pattern:
👉 A collapsible header 👉 A sticky tab bar 👉 Smooth scroll sync across tabs
Think of apps like banking or portfolio dashboards — the header shrinks, tabs stick, and content scrolls seamlessly.
I recently implemented this pattern from scratch using React Native + Reanimated, and I wanted to share both:
- A basic version (no animation)
- A fully functional collapsible sticky header setup
👉 Repo structure:
- basic branch → simple FlatList + header
- main branch → sticky + collapsible + synced tabs
Link: https://github.com/imanshul/CollapsibleStickyTabHeader
🧱 Step 1: The Basic Layout (Before)
We start simple — just a header, tab bar, and conditional rendering.

Basic layout with header
const Home = () => {
const [activeTab, setActiveTab] = useState(TABS.OVERVIEW);
return (
<View style={{ flex: 1 }}>
<Header ... />
<CustomTabBar selectedTab={activeTab} onTabPress={setActiveTab} />
{activeTab === TABS.OVERVIEW && <OverviewTab />}
{activeTab === TABS.HISTORY && <HistoryTab />}
</View>
);
};
Each tab is just a FlatList.
👉 Problem:
- Header stays blocking half the screen
- Switching tabs resets scroll
🚀 Step 2: Making Header Collapsible
We move the header into an absolute positioned animated container.
Core idea:
- Track scroll position
- Translate header upward until collapsed
const translateY = useDerivedValue(() =>
-Math.min(currentScrollValue.value, headerDiff)
);
This is the entire trick.
👉 Header moves up 👉 Stops exactly when collapsed 👉 Tab bar remains visible
🎯 Step 3: Measure Header Dynamically
Hardcoding header height is a rookie mistake.
Instead:
const handleHeaderLayout = (event) =>
setHeaderHeight(event.nativeEvent.layout.height);
Then compute:
const headerDiff = heightExpanded - heightCollapsed;
Now your animation adapts to:
- different devices
- dynamic content
- safe areas
📜 Step 4: Push Content Below Header
Since header is position: absolute, content would overlap.
Fix:
contentContainerStyle={{
paddingTop: headerHeight,
}}
Bonus:
minHeight: screenHeight + headerDiff
👉 Prevents scroll glitches when content is small.
🔄 Step 5: Sync Scroll Between Tabs (Important)
Without this, switching tabs feels broken.
Each tab maintains its own scroll:
const overviewScrollValue = useSharedValue(0);
const historyScrollValue = useSharedValue(0);
Then we sync them using a custom hook:
const scrollPairs = [
{ list: overviewRef, position: overviewScrollValue },
{ list: historyRef, position: historyScrollValue },
];
👉 When you switch tabs:
- Header stays collapsed
- Scroll position feels continuous
🧠 Step 6: Render Tabs Smartly
Instead of mounting/unmounting:
<View style={styles.tabContentAbsolute}>
We:
- Stack tabs on top of each other
- Toggle visibility using opacity
- Control interaction using pointerEvents
pointerEvents={activeTab === TABS.OVERVIEW ? "auto" : "none"}
👉 This preserves scroll state 🔥
⚡ Step 7: Use Animated.FlatList + forwardRef
To control scroll programmatically:
const OverviewTab = forwardRef<FlatList, Props>((props, ref) => {
return (
<Animated.FlatList
ref={ref}
{...props}
/>
);
});
👉 This enables:
- scroll sync
- imperative control
- better performance
🎨 Final Result

Collapsible Scroll with sticky tab header
You now get:
✅ Smooth collapsing header ✅ Sticky tab bar ✅ Synced scroll across tabs ✅ No layout jumps ✅ Production-ready pattern
📦 Repo
Check out both implementations here:
- basic → starting point
- main → full collapsible experience
💬 Final Thoughts
This pattern looks simple but has a lot of moving parts:
- layout
- animation
- gesture sync
- rendering strategy
Once you understand it, you can reuse it everywhere:
- dashboards
- profiles
- analytics screens
- fintech apps (my use case)
If this helped you, hit the 👏🏻 to show some love and help others find it too.
메타데이터
- post_id
- 42ac55cf3bf9
- slug
- building-a-smooth-collapsible-header-with-sticky-tabs-in-react-native-42ac55cf3bf9
- url
- https://medium.com/@imanshul/building-a-smooth-collapsible-header-with-sticky-tabs-in-react-native-42ac55cf3bf9
- canonical_url
- https://medium.com/@imanshul/building-a-smooth-collapsible-header-with-sticky-tabs-in-react-native-42ac55cf3bf9
- author_url
- https://medium.com/@imanshul
- status
- ok
- fetched_at
- 2026-08-11 04:34:46