List
The List component provides a beautiful container for vertical lists with automatic borders, padding, and virtualization support.
Import
import { List } from 'papillon-ui';
Basic Usage
import { List, Item, Typography } from 'papillon-ui';
<List>
<Item onPress={() => {}}>
<Typography variant="title">First Item</Typography>
</Item>
<Item onPress={() => {}}>
<Typography variant="title">Second Item</Typography>
</Item>
<Item onPress={() => {}}>
<Typography variant="title">Third Item</Typography>
</Item>
</List>
Props
Array of data items to render. When provided, enables automatic virtualization for large lists.
Child elements to render inside the list. Use this for static lists.
Removes automatic padding from non-Item children.
Suppresses the bottom border for all items in the list.
Enables layout transition animations.
Border radius of the list container.
Bottom margin of the list container.
Style applied to the content container of each list item.
Custom Reanimated entering animation.
Custom Reanimated exiting animation.
Disables item layout animations for better performance.
With Data Array
For large lists, use the data prop to enable automatic virtualization:
const items = [
{ id: '1', title: 'Grades', icon: 'star' },
{ id: '2', title: 'Homework', icon: 'book' },
{ id: '3', title: 'Timetable', icon: 'calendar' },
];
<List data={items}>
{items.map(item => (
<Item key={item.id} onPress={() => {}}>
<Typography variant="title">{item.title}</Typography>
</Item>
))}
</List>
When the data array contains 20+ items, List automatically uses @legendapp/list for virtualization.
Automatic Borders
List automatically adds borders between items:
<List>
<Item><Typography>Item 1</Typography></Item>
<Item><Typography>Item 2</Typography></Item> {/* Border above */}
<Item><Typography>Item 3</Typography></Item> {/* Border above */}
</List>
Disable Borders
<List ignoreBorder>
<Item><Typography>No borders</Typography></Item>
<Item><Typography>Between items</Typography></Item>
</List>
Automatic Padding
Non-Item children automatically receive padding:
<List>
<Typography variant="title">Auto-padded title</Typography>
<Typography variant="caption">Auto-padded caption</Typography>
</List>
Disable Padding
<List disablePadding>
<View style={{ padding: 20 }}>
<Typography>Custom padding</Typography>
</View>
</List>
Mixed Content
Combine Item components with custom children:
<List>
<View style={{ padding: 16 }}>
<Typography variant="h5">Section Header</Typography>
</View>
<Item><Typography>Item 1</Typography></Item>
<Item><Typography>Item 2</Typography></Item>
<View style={{ padding: 16 }}>
<Typography variant="caption" color="secondary">
2 items
</Typography>
</View>
</List>
Styling
Custom Border Radius
<List radius={12}>
<Item><Typography>Smaller radius</Typography></Item>
</List>
<List radius={30}>
<Item><Typography>Larger radius</Typography></Item>
</List>
Custom Spacing
<List marginBottom={24}>
<Item><Typography>More bottom margin</Typography></Item>
</List>
Content Container Style
Apply styles to all list item containers:
<List contentContainerStyle={{ paddingHorizontal: 20 }}>
<Item><Typography>Extra horizontal padding</Typography></Item>
</List>
Animations
Entry/Exit Animations
import { FadeIn, FadeOut } from 'react-native-reanimated';
<List
entering={FadeIn.duration(300)}
exiting={FadeOut.duration(200)}
>
<Item><Typography>Animated list</Typography></Item>
</List>
Disable Animations
For performance optimization:
<List animated={false} disableItemAnimation>
{longArray.map(item => (
<Item key={item.id}>
<Typography>{item.name}</Typography>
</Item>
))}
</List>
Virtualization Threshold
List automatically virtualizes when data has 20+ items:
const manyItems = Array.from({ length: 100 }, (_, i) => ({
id: i,
name: `Item ${i}`
}));
<List data={manyItems}> {/* Automatically virtualized */}
{manyItems.map(item => (
<Item key={item.id}>
<Typography>{item.name}</Typography>
</Item>
))}
</List>
Memoization
List uses aggressive memoization:
- Shallow comparison of
data and children props
- Cached style calculations
- Pre-computed border and padding styles
Disable Animations for Long Lists
<List
data={longArray}
disableItemAnimation // Better performance
animated={false}
>
{/* Items */}
</List>
Theming
List automatically uses your React Navigation theme:
import { useTheme } from '@react-navigation/native';
function ThemedList() {
const { colors } = useTheme();
// List automatically uses:
// - colors.card for background
// - colors.border for border
// - colors.text + opacity for item separators
return (
<List>
<Item><Typography>Themed list</Typography></Item>
</List>
);
}
Accessibility
<List
accessible
accessibilityRole="list"
accessibilityLabel="Settings menu"
>
<Item accessibilityRole="button">
<Typography>Setting 1</Typography>
</Item>
</List>
Best Practices
Use data prop for dynamic lists
When rendering lists from API data or state, use the data prop to enable automatic virtualization:const { data: grades } = useGrades();
<List data={grades}>
{grades.map(grade => (
<GradeItem key={grade.id} grade={grade} />
))}
</List>
For optimal performance, wrap list items in React.memo:const MemoizedItem = React.memo(({ item }) => (
<Item onPress={() => {}}>
<Typography>{item.title}</Typography>
</Item>
));
<List data={items}>
{items.map(item => <MemoizedItem key={item.id} item={item} />)}
</List>
Use Item component for pressable rows
Always use the Item component for pressable list rows to get proper animations and styling:<List>
<Item onPress={() => {}}> {/* Good */}
<Typography>Pressable</Typography>
</Item>
</List>
Full Example
import { List, Item, Typography } from 'papillon-ui';
import { ChevronRight, User, Settings, Bell } from 'lucide-react-native';
function SettingsList() {
const settings = [
{ id: '1', title: 'Profile', icon: User, route: '/profile' },
{ id: '2', title: 'Notifications', icon: Bell, route: '/notifications' },
{ id: '3', title: 'Settings', icon: Settings, route: '/settings' },
];
return (
<List data={settings} radius={20}>
{settings.map(setting => (
<Item key={setting.id} onPress={() => navigate(setting.route)}>
<Item.Leading>
<setting.icon size={24} />
</Item.Leading>
<Typography variant="title">{setting.title}</Typography>
<Item.Trailing>
<ChevronRight size={20} />
</Item.Trailing>
</Item>
))}
</List>
);
}