Item
The Item component is an optimized list row with automatic borders, press animations, and support for leading/trailing elements.
Import
import { Item } from 'papillon-ui' ;
Basic Usage
import { Item , Typography } from 'papillon-ui' ;
< Item onPress = { () => console . log ( 'Pressed' ) } >
< Typography variant = "title" > Basic Item </ Typography >
< Typography variant = "caption" color = "secondary" > Subtitle text </ Typography >
</ Item >
Props
Callback fired when the item is pressed.
Content to display in the item. Automatically arranged based on Leading/Trailing components.
Enables enter/exit animations for the item.
Style applied to the content container (middle section).
Style applied to the entire item container.
Automatically set by List component. Removes bottom border when true.
Removes default padding from the item.
Leading and Trailing
Use Item.Leading and Item.Trailing for icons or badges:
import { Item , Typography } from 'papillon-ui' ;
import { User , ChevronRight , Bell } from 'lucide-react-native' ;
< Item onPress = { () => {} } >
< Item.Leading >
< User size = { 24 } />
</ Item.Leading >
< Typography variant = "title" > Profile </ Typography >
< Typography variant = "caption" color = "secondary" >
View your profile settings
</ Typography >
< Item.Trailing >
< ChevronRight size = { 20 } />
</ Item.Trailing >
</ Item >
Content Arrangement
The Item component automatically arranges children:
Leading elements appear first (left side)
Content (other children) fills the center with flex
Trailing elements appear last (right side)
< Item >
< Item.Leading > { /* Left */ }
< Icon />
</ Item.Leading >
< Typography > { /* Center (flex: 1) */ }
Main Content
</ Typography >
< Item.Trailing > { /* Right */ }
< Badge />
</ Item.Trailing >
</ Item >
Press Animations
Item includes smooth press animations:
const [ isPressed , setIsPressed ] = useState ( false );
< Item
onPress = { () => {} }
onPressIn = { () => setIsPressed ( true ) }
onPressOut = { () => setIsPressed ( false ) }
>
< Typography > Animated on press </ Typography >
</ Item >
Animation behavior:
Press In : Scales to 0.97 and reduces opacity to 0.7
Press Out : Springs back with smooth easing
Runs on UI thread via Reanimated worklets
Multiple Content Lines
Stack multiple elements vertically:
< Item onPress = { () => {} } >
< Typography variant = "title" > Primary Text </ Typography >
< Typography variant = "body2" color = "secondary" >
Secondary text
</ Typography >
< Typography variant = "caption" color = "secondary" >
Additional info
</ Typography >
</ Item >
With Badges
< Item onPress = { () => {} } >
< Item.Leading >
< Bell size = { 24 } />
</ Item.Leading >
< Typography variant = "title" > Notifications </ Typography >
< Item.Trailing >
< View style = { {
backgroundColor: '#FF3B30' ,
borderRadius: 12 ,
paddingHorizontal: 8 ,
paddingVertical: 2
} } >
< Typography color = "light" variant = "caption" > 3 </ Typography >
</ View >
</ Item.Trailing >
</ Item >
Nested Layout
Combine with other components:
import { Stack } from 'papillon-ui' ;
< Item onPress = { () => {} } >
< Item.Leading >
< Avatar size = { 40 } />
</ Item.Leading >
< Stack gap = { 2 } >
< Typography variant = "title" > John Doe </ Typography >
< Typography variant = "caption" color = "secondary" >
[email protected]
</ Typography >
</ Stack >
< Item.Trailing >
< CheckIcon />
</ Item.Trailing >
</ Item >
Custom Padding
< Item
disablePadding
style = { { paddingVertical: 20 , paddingHorizontal: 24 } }
>
< Typography > Custom padded item </ Typography >
</ Item >
Without Press Effect
Omit onPress for non-interactive items:
< Item >
< Typography variant = "title" > Non-interactive </ Typography >
< Typography variant = "caption" > No press animation </ Typography >
</ Item >
Extreme Optimization Techniques:
Memoized with custom areEqual function for minimal re-renders
Pre-computed style objects to avoid recreation
Shared values for animations (single animationValue instead of separate scale/opacity)
Border color caching with WeakMap
Early returns to skip rendering when unnecessary
Minimal allocations in children sorting
const MemoizedItem = React . memo (({ data }) => (
< Item onPress = { () => {} } >
< Typography > { data . title } </ Typography >
</ Item >
));
Theming
Item uses your React Navigation theme:
import { useTheme } from '@react-navigation/native' ;
function ThemedItem () {
const { colors } = useTheme ();
// Item automatically uses:
// - colors.text + "25" for border color
return (
< Item onPress = { () => {} } >
< Typography > Themed item </ Typography >
</ Item >
);
}
Best Practices
Always use with List component
Items are designed to work inside List containers: < List >
< Item >< Typography > Item 1 </ Typography ></ Item >
< Item >< Typography > Item 2 </ Typography ></ Item >
</ List >
Use Leading/Trailing for icons
Always wrap icons in Leading/Trailing for proper alignment: < Item >
< Item.Leading >< Icon /></ Item.Leading >
< Typography > Text </ Typography >
< Item.Trailing >< Badge /></ Item.Trailing >
</ Item >
When rendering many items, wrap in React.memo: const MemoItem = React . memo ( ItemComponent );
Accessibility
< Item
onPress = { () => {} }
accessibilityRole = "button"
accessibilityLabel = "View profile"
accessibilityHint = "Double tap to view your profile settings"
>
< Typography > Profile </ Typography >
</ Item >
Full Example
import { List , Item , Typography , Stack } from 'papillon-ui' ;
import { User , Mail , Phone , MapPin , ChevronRight } from 'lucide-react-native' ;
import { useTheme } from '@react-navigation/native' ;
function ContactList ({ contacts }) {
const { colors } = useTheme ();
return (
< List >
{ contacts . map ( contact => (
< Item
key = { contact . id }
onPress = { () => navigate ( 'ContactDetail' , { id: contact . id }) }
>
< Item.Leading >
< View style = { {
width: 48 ,
height: 48 ,
borderRadius: 24 ,
backgroundColor: contact . color + '30' ,
alignItems: 'center' ,
justifyContent: 'center'
} } >
< User size = { 24 } color = { contact . color } />
</ View >
</ Item.Leading >
< Stack gap = { 4 } >
< Typography variant = "title" > { contact . name } </ Typography >
< Stack direction = "horizontal" gap = { 12 } >
< Stack direction = "horizontal" gap = { 4 } >
< Mail size = { 14 } color = { colors . text + '80' } />
< Typography variant = "caption" color = "secondary" >
{ contact . email }
</ Typography >
</ Stack >
< Stack direction = "horizontal" gap = { 4 } >
< Phone size = { 14 } color = { colors . text + '80' } />
< Typography variant = "caption" color = "secondary" >
{ contact . phone }
</ Typography >
</ Stack >
</ Stack >
</ Stack >
< Item.Trailing >
< ChevronRight size = { 20 } color = { colors . text + '60' } />
</ Item.Trailing >
</ Item >
)) }
</ List >
);
}