How to build an accordion in React Native
By the LumioUI team · Updated
An accordion is a list of sections that expand in place to show more. In React Native, measure each section's content, then animate the container's height from 0 to the measured height with Reanimated while the chevron rotates. Mark the header expanded for screen readers. The LumioUI Accordion grows each section in place and gently pushes the content below.
Live demo of the LumioUI Accordion component. It's interactive, so try it.
How an accordion animates
- Measure the body. React Native can't animate to
height: "auto", so render the content off-flow once and read its height withonLayout. - Animate one progress value. Height and chevron rotation both come from the same 0 to 1 value, so they always agree. Spring it open and close it a little faster.
- Clip, don't scale. Use
overflow: "hidden"on the animated container so the text is revealed, not squashed. - Single or multiple. FAQs usually allow one open section at a time, while settings screens often allow several. Hold the open keys in state either way.
- Accessibility. The header is a button with
accessibilityState.expanded, so screen readers say "collapsed" or "expanded".
import * as React from "react";
import { Pressable, Text, View } from "react-native";
import Animated, { useAnimatedStyle, useSharedValue, withSpring, withTiming } from "react-native-reanimated";
export function Section({ title, children }: { title: string; children: React.ReactNode }) {
const [open, setOpen] = React.useState(false);
const contentH = useSharedValue(0); // measured height of the body
const progress = useSharedValue(0); // 0 closed → 1 open
const toggle = () => {
setOpen((o) => !o);
progress.value = open ? withTiming(0, { duration: 180 }) : withSpring(1, { damping: 20, stiffness: 220 });
};
const body = useAnimatedStyle(() => ({ height: contentH.value * progress.value, overflow: "hidden" }));
const chevron = useAnimatedStyle(() => ({ transform: [{ rotate: `${progress.value * 180}deg` }] }));
return (
<View>
<Pressable onPress={toggle} accessibilityRole="button" accessibilityState={{ expanded: open }}>
<Text>{title}</Text>
<Animated.Text style={chevron}>⌄</Animated.Text>
</Pressable>
<Animated.View style={body}>
{/* Measured off-flow so the height is known before opening */}
<View style={{ position: "absolute", width: "100%" }} onLayout={(e) => (contentH.value = e.nativeEvent.layout.height)}>
{children}
</View>
</Animated.View>
</View>
);
} The quick way: LumioUI Accordion
The Accordion handles measuring, motion, reduced motion and accessibility. Open sections also round their corners, so a group reads as one surface. It's free and runs in Expo Go.
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion/accordion";
import { Text } from "@/components/ui/text/text";
export function Faq() {
return (
<Accordion type="single" collapsible defaultValue={["refunds"]}>
<AccordionItem value="refunds">
<AccordionTrigger>Can I get a refund?</AccordionTrigger>
<AccordionContent><Text>Yes, within 14 days of purchase.</Text></AccordionContent>
</AccordionItem>
<AccordionItem value="devices">
<AccordionTrigger>How many devices can I use?</AccordionTrigger>
<AccordionContent><Text>As many as you like on one account.</Text></AccordionContent>
</AccordionItem>
</Accordion>
);
} type="single"(the default) or"multiple".collapsiblelets the open section close again.value,defaultValueandonValueChangetake arrays of item values.lithighlights the section you open.AccordionItemtakesdisabled.- For one standalone expanding block, use Collapsible.
Add it to your app
LumioUI's CLI copies the component's source into your project, so it's yours to read and change. Run init once per project:
npx @lumioui/cli init
npx @lumioui/cli add accordion It works in Expo (SDK 54+) and bare React Native, with Reanimated 4 and NativeWind. See the installation guide and the full Accordion API.
Related components
More React Native guides
- How to make a bottom sheet in React Native
- Animated tabs with a sliding indicator in React Native
- How to show toast notifications in React Native
- Skeleton loading screens in React Native
- How to add dark mode and a theme toggle in React Native
- How to make a side drawer menu in React Native
- How to make an animated heart like button in React Native
- How to make a modal dialog in React Native
- How to build an animated carousel in React Native
- How to make an animated splash screen in React Native and Expo
- How to build a month calendar in React Native