Collapsible
An expandable section that reveals or hides content with smooth animated transitions.
The Collapsible component is an expandable/collapsible section that smoothly reveals or hides its content. It uses React Native Reanimated for animated height transitions and supports controlled and uncontrolled state with a compound component API.
Preview
Installation
npx novaui-cli add collapsibleDependencies
The Collapsible requires the following peer dependencies:
react-native-reanimated>= 3
Import
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from 'novaui-components'Basic Usage
The Collapsible is a compound component with three parts:
Collapsible- Root container with open/close stateCollapsibleTrigger- The clickable element that toggles visibilityCollapsibleContent- The content that expands/collapses with animation
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from 'novaui-components'
import { View, Text, Pressable } from 'react-native'
import { ChevronsUpDown } from 'lucide-react-native'
export function BasicCollapsible() {
return (
<Collapsible>
<View className="flex-row items-center justify-between space-x-4 px-4">
<Text className="text-sm font-semibold">
@peduarte starred 3 repositories
</Text>
<CollapsibleTrigger>
<Pressable className="p-2 rounded-md border border-input">
<ChevronsUpDown size={16} />
</Pressable>
</CollapsibleTrigger>
</View>
<View className="rounded-md border border-border px-4 py-3 mt-2">
<Text className="text-sm">@radix-ui/primitives</Text>
</View>
<CollapsibleContent>
<View className="flex flex-col gap-2 mt-2">
<View className="rounded-md border border-border px-4 py-3">
<Text className="text-sm">@radix-ui/colors</Text>
</View>
<View className="rounded-md border border-border px-4 py-3">
<Text className="text-sm">@stitches/react</Text>
</View>
</View>
</CollapsibleContent>
</Collapsible>
)
}Default Open
Start with content already visible using defaultOpen:
<Collapsible defaultOpen>
<View className="flex-row items-center justify-between space-x-4 px-4">
<Text className="text-sm font-semibold">3 items available</Text>
<CollapsibleTrigger>
<Pressable className="p-2 rounded-md border border-input">
<ChevronsUpDown size={16} />
</Pressable>
</CollapsibleTrigger>
</View>
<View className="rounded-md border border-border px-4 py-3 mt-2">
<Text className="text-sm">First item (always visible)</Text>
</View>
<CollapsibleContent>
<View className="flex flex-col gap-2 mt-2">
<View className="rounded-md border border-border px-4 py-3">
<Text className="text-sm">Second item (collapsible)</Text>
</View>
<View className="rounded-md border border-border px-4 py-3">
<Text className="text-sm">Third item (collapsible)</Text>
</View>
</View>
</CollapsibleContent>
</Collapsible>Controlled State
Control the collapsible state programmatically:
import { useState } from 'react'
export function ControlledCollapsible() {
const [open, setOpen] = useState(false)
return (
<View>
<Button
label={open ? 'Hide Details' : 'Show Details'}
variant="outline"
onPress={() => setOpen(!open)}
/>
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleContent>
<View className="rounded-md border border-border px-4 py-3 mt-2">
<Text className="text-sm">
These are the details that can be toggled externally.
</Text>
</View>
</CollapsibleContent>
</Collapsible>
</View>
)
}Props API
Collapsible Props
Extends React.ComponentPropsWithoutRef<typeof View> and includes:
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state |
onOpenChange | (open: boolean) => void | - | Callback when open state changes |
defaultOpen | boolean | false | Initial open state (uncontrolled) |
disabled | boolean | false | Disable toggling |
CollapsibleTrigger Props
Extends React.ComponentPropsWithoutRef<typeof Pressable>:
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Render as the child element instead of a Pressable |
CollapsibleContent Props
Extends React.ComponentPropsWithoutRef<typeof View>:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the content wrapper |
Animation
The Collapsible uses react-native-reanimated for smooth height transitions:
- Height animation: Content height animates from 0 to measured height using
withTiming - Opacity: Content fades in/out during the transition
- Overflow hidden: The animated wrapper clips content during transitions
Best Practices
-
Always-visible item: Place one item outside
CollapsibleContentas a preview, then put the rest inside the collapsible area -
Clear trigger: Make the toggle button obvious — use icons like
ChevronsUpDownor descriptive text -
Smooth transitions: The Reanimated-powered animation measures content height automatically — no fixed heights needed
-
Don't nest collapsibles: Avoid deeply nested collapsible sections — use
Accordionfor multiple collapsible items -
Accessible labels: Use
asChildonCollapsibleTriggerfor custom trigger elements
Related Components
- Use
Accordionfor multiple collapsible sections with single/multi expand - Use
Tabsfor switching between different content views - Use
Cardto wrap collapsible sections for visual grouping