AniUI

Collapsible

Animated collapsible container that can be toggled open and closed.

Subtotal$76.00

Shipping$4.50

Tax$4.00

Web preview — components render natively on iOS & Android
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@/components/ui/collapsible";

export function MyScreen() {
  const [open, setOpen] = useState(false);
  return (
    <Collapsible open={open} onOpenChange={setOpen}>
      <CollapsibleTrigger>
        <Text>{open ? "Hide" : "Show"} price breakdown</Text>
      </CollapsibleTrigger>
      <CollapsibleContent>
        <Text>Subtotal: $76.00</Text>
        <Text>Shipping: $4.50</Text>
        <Text>Tax: $4.00</Text>
      </CollapsibleContent>
    </Collapsible>
  );
}

Installation#

npx @aniui/cli add collapsible

This component requires react-native-reanimated for animations.

Usage#

app/index.tsx
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@/components/ui/collapsible";

export function MyScreen() {
  const [open, setOpen] = useState(false);
  return (
    <Collapsible open={open} onOpenChange={setOpen}>
      <CollapsibleTrigger>
        <Text>{open ? "Hide" : "Show"} price breakdown</Text>
      </CollapsibleTrigger>
      <CollapsibleContent>
        <Text>Subtotal: $76.00</Text>
        <Text>Shipping: $4.50</Text>
        <Text>Tax: $4.00</Text>
      </CollapsibleContent>
    </Collapsible>
  );
}

Controlled#

Use the open and onOpenChange props for controlled behavior.

app/index.tsx
const [open, setOpen] = useState(false);
<Collapsible open={open} onOpenChange={setOpen}>
  <CollapsibleTrigger>
    <Text>{open ? "Hide" : "Show"} details</Text>
  </CollapsibleTrigger>
  <CollapsibleContent>
    <Text>Controlled collapsible content.</Text>
  </CollapsibleContent>
</Collapsible>

Compound Components#

ComponentDescription
Collapsible

Root container managing open/closed state

CollapsibleTrigger

Pressable element that toggles the content

CollapsibleContent

Animated container for collapsible content

Props#

Collapsible#

PropTypeDefault
open
boolean
false (uncontrolled)
onOpenChange
(open: boolean) => void
className
string

Accessibility#

  • Uses React Context with Reanimated FadeIn/FadeOut animations
  • Trigger button announces expanded/collapsed state to screen readers.

Source#

components/ui/collapsible.tsx
import React, { createContext, useContext, useState } from "react";
import { View, Pressable } from "react-native";
import Animated from "react-native-reanimated";
import { entering, exiting } from "@/components/ui/animate";
import { cn } from "@/lib/utils";

const CollapsibleCtx = createContext<{ isOpen: boolean; toggle: () => void }>({ isOpen: false, toggle: () => {} });

export interface CollapsibleProps extends React.ComponentPropsWithoutRef<typeof View> {
  className?: string;
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
  children?: React.ReactNode;
}

export function Collapsible({ open: controlledOpen, onOpenChange, className, children, ...props }: CollapsibleProps) {
  const [uncontrolled, setUncontrolled] = useState(false);
  const isOpen = controlledOpen ?? uncontrolled;
  const toggle = () => {
    const next = !isOpen;
    setUncontrolled(next);
    onOpenChange?.(next);
  };

  return (
    <CollapsibleCtx.Provider value={{ isOpen, toggle }}>
      <View className={cn("", className)} {...props}>{children}</View>
    </CollapsibleCtx.Provider>
  );
}

export interface CollapsibleTriggerProps extends React.ComponentPropsWithoutRef<typeof Pressable> {
  className?: string;
  children?: React.ReactNode;
}

export function CollapsibleTrigger({ className, children, ...props }: CollapsibleTriggerProps) {
  const { toggle } = useContext(CollapsibleCtx);
  return (
    <Pressable className={cn("", className)} onPress={toggle} accessible={true} accessibilityRole="button" {...props}>
      {children}
    </Pressable>
  );
}

export interface CollapsibleContentProps extends React.ComponentPropsWithoutRef<typeof View> {
  className?: string;
  children?: React.ReactNode;
}

export function CollapsibleContent({ className, children, ...props }: CollapsibleContentProps) {
  const { isOpen } = useContext(CollapsibleCtx);
  if (!isOpen) return null;
  return (
    <Animated.View entering={entering.fadeInDown} exiting={exiting.fadeOutUp}>
      <View className={cn("", className)} {...props}>{children}</View>
    </Animated.View>
  );
}