← Back to list

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

Anshul Thakur · 2026-03-23 06:43 · 1 claps · 2.8 min read
#react-native #reanimated #stickyheader #scrollview #mobile-app-development
Open on Medium ↗
Wiki topics: 🌐 · Web Development 📱 · Mobile Development

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

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

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

[embed]GitHub - imanshul/CollapsibleStickyTabHeader: A React Native demo application showcasing how to… A React Native demo application showcasing how to implement a collapsible sticky tab header with synchronized…github.com

💬 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