React Native Collapsible Sections and Accordions

To collapse a section in React Native, keep an open flag in state and render the body only while it is true. Call LayoutAnimation.configureNext before changing the flag and the surrounding views slide to their new positions. Give the header Pressable accessibilityRole="button" and accessibilityState={{ expanded }} so screen readers announce whether it is open.

Two ways to animate a collapsible
MethodAnimatesGood for
LayoutAnimation.configureNextThe next layout change of every viewBodies of unknown height, lists of sections
Animated.timing with useNativeDriverNon-layout properties such as transform and opacityThe chevron rotation and fades
Animated with heightHeight, on the JS threadFixed-height panels when you need fine control

Updated

The accordion below is the web twin of the React Native code on this page: same state shape, same expanded flag on each header. Switch between letting several sections stay open and allowing only one, then copy the version that fits your screen.

Accordion preview

Sample help questions from a made-up store, to show the behaviour.

Collapsible code

Collapsible section with LayoutAnimation and a rotating chevron

The body mounts only while open. The chevron turns with the native driver because rotation is a transform.

import { useEffect, useRef, useState } from "react";
import {
  Animated, LayoutAnimation, Platform, Pressable, StyleSheet, Text, UIManager, View,
} from "react-native";

if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
  UIManager.setLayoutAnimationEnabledExperimental(true);
}

export function Collapsible({ title, open, onToggle, children }) {
  const turn = useRef(new Animated.Value(open ? 1 : 0)).current;
  useEffect(() => {
    Animated.timing(turn, { toValue: open ? 1 : 0, duration: 200, useNativeDriver: true }).start();
  }, [open, turn]);
  const rotate = turn.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "180deg"] });

  const press = () => {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
    onToggle();
  };

  return (
    <View style={s.item}>
      <Pressable
        accessibilityRole="button"
        accessibilityState={{ expanded: open }}
        onPress={press}
        style={s.header}
      >
        <Text style={s.title}>{title}</Text>
        <Animated.Text style={{ transform: [{ rotate }] }}>⌄</Animated.Text>
      </Pressable>
      {open ? <View style={s.body}>{children}</View> : null}
    </View>
  );
}

const s = StyleSheet.create({
  item: { borderBottomWidth: 1, borderColor: "#e5e7eb" },
  header: { flexDirection: "row", justifyContent: "space-between", padding: 16 },
  title: { fontWeight: "600", flexShrink: 1 },
  body: { paddingHorizontal: 16, paddingBottom: 16 },
});

Accordion: one section open at a time

A single id in state. Pressing the open section again sets it to null and closes it.

export function Accordion({ items }) {
  const [openId, setOpenId] = useState(null);
  return items.map((item) => (
    <Collapsible
      key={item.id}
      title={item.title}
      open={openId === item.id}
      onToggle={() => setOpenId((cur) => (cur === item.id ? null : item.id))}
    >
      <Text>{item.body}</Text>
    </Collapsible>
  ));
}

Accordion or independent sections

An accordion keeps one section open, which suits settings screens and short FAQs where the reader wants one answer. Independent sections suit filters or order details, where comparing two open panels is useful.

Both use the same component; only the toggle function changes. Store a Set of ids for independent sections, or a single id that becomes null when the open one is pressed again.

Keeping it smooth

LayoutAnimation configures only the very next layout, so call it in the press handler, immediately before setState, every time. Calling it once at mount has no effect on later presses.

Very long bodies can still stutter on low-end phones. Keep heavy lists inside a section lazy, or render a short preview with a link to a full screen.

How it works

  1. State holds the ids of the open sections, or a single id when only one may be open.
  2. Pressing a header calls LayoutAnimation.configureNext with a preset, then updates the state.
  3. On the next layout pass the body mounts or unmounts and its neighbours animate into place.
  4. An Animated value rotates the chevron with the native driver, since rotation is a transform.
  5. accessibilityState expanded on the header tells assistive tech which sections are open.

Tips

Frequently asked questions

How do I animate a collapsible view in React Native?

Call LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) right before the state change that shows or hides the body. The easeInEaseOut preset runs for 300 milliseconds.

Why does LayoutAnimation do nothing on Android?

The LayoutAnimation page says Android needs UIManager.setLayoutAnimationEnabledExperimental(true), called only if that function exists. Run it once when the app starts, before the first animated change.

Can I animate height with Animated and the native driver?

No. The React Native docs limit the native driver to non-layout properties such as transform and opacity, so layout values like height are out. Animate height without the native driver, or use LayoutAnimation instead.

How do screen readers know a section is open?

Set accessibilityState={{ expanded: isOpen }} on the header, or the aria-expanded prop. The docs describe expanded as whether an expandable element is currently expanded or collapsed.

Related: React Native radio buttons, React Native dropdown, aria-label examples, React hooks cheat sheet, React vs React Native.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap