Card Component
The Card component is a versatile container with an elevation system that automatically adjusts background colors based on the theme. It includes optional title and description props, animated press feedback, and flexible children support.
Import
import { Card } from "@/components/Card" ;
Basic Usage
Simple Card
Card with Title
Pressable Card
Elevated Card
import { Card } from "@/components/Card" ;
import { ThemedText } from "@/components/ThemedText" ;
function MyScreen () {
return (
< Card >
< ThemedText > Card content goes here </ ThemedText >
</ Card >
);
}
Props
Elevation level that determines the background color:
0: theme.backgroundRoot
1: theme.backgroundDefault
2: theme.backgroundSecondary
3: theme.backgroundTertiary
Optional title displayed at the top of the card using ThemedText with h4 typography
Optional description displayed below the title with reduced opacity (0.7) and small typography
Content to render inside the card
Callback function invoked when the card is pressed. When provided, the card becomes interactive with press animations
Additional styles to apply to the card container
Real-World Examples
From GoalsScreen.tsx:156-161:
< Card style = { styles . section } >
< ThemedText style = { styles . sectionTitle } >
T1 - Main Lifts (1RM Goals)
</ ThemedText >
{ mainLifts . map (( exercise ) => renderExerciseInput ( exercise )) }
</ Card >
This demonstrates using Card as a grouping container for related inputs, with custom styling applied.
Elevation System
The Card component uses a semantic elevation system for visual hierarchy:
Elevation 0
Elevation 1 (Default)
Elevation 2
Elevation 3
Background : theme.backgroundRootUsed for the lowest level, typically matching the root background. < Card elevation = { 0 } >
Root level content
</ Card >
Background : theme.backgroundDefaultThe default elevation for most cards. < Card elevation = { 1 } >
Standard card content
</ Card >
Background : theme.backgroundSecondaryUsed for cards that need to appear above default cards. < Card elevation = { 2 } >
Raised content
</ Card >
Background : theme.backgroundTertiaryHighest elevation for important or floating elements. < Card elevation = { 3 } >
Highly elevated content
</ Card >
Animation Behavior
When onPress is provided, the Card becomes animated:
Press Animation
const handlePressIn = () => {
scale . value = withSpring ( 0.98 , springConfig );
};
const handlePressOut = () => {
scale . value = withSpring ( 1 , springConfig );
};
Press In : Scales down to 0.98
Press Out : Springs back to 1.0
Spring Config : Same configuration as Button for consistency
Styling
Default Styles
const styles = StyleSheet . create ({
card: {
padding: Spacing . xl ,
borderRadius: BorderRadius [ "2xl" ],
},
cardTitle: {
marginBottom: Spacing . sm ,
},
cardDescription: {
opacity: 0.7 ,
},
});
Custom Styling Example
< Card
style = { {
marginBottom: 16 ,
paddingVertical: 20 ,
} }
title = "Custom Card"
>
< ThemedText > Content </ ThemedText >
</ Card >
Layout Patterns
Vertical Stack
function MyScreen () {
return (
< ScrollView >
< Card title = "First Section" style = { { marginBottom: 16 } } >
< ThemedText > Content 1 </ ThemedText >
</ Card >
< Card title = "Second Section" style = { { marginBottom: 16 } } >
< ThemedText > Content 2 </ ThemedText >
</ Card >
< Card title = "Third Section" >
< ThemedText > Content 3 </ ThemedText >
</ Card >
</ ScrollView >
);
}
Horizontal Grid
function MyScreen () {
return (
< View style = { { flexDirection: 'row' , gap: 12 } } >
< Card style = { { flex: 1 } } title = "Card 1" >
< ThemedText > Content </ ThemedText >
</ Card >
< Card style = { { flex: 1 } } title = "Card 2" >
< ThemedText > Content </ ThemedText >
</ Card >
</ View >
);
}
TypeScript Interface
interface CardProps {
elevation ?: number ;
title ?: string ;
description ?: string ;
children ?: React . ReactNode ;
onPress ?: () => void ;
style ?: ViewStyle ;
}
Background Color Helper
The Card uses an internal helper function to determine background color:
const getBackgroundColorForElevation = (
elevation : number ,
theme : any ,
) : string => {
switch ( elevation ) {
case 1 :
return theme . backgroundDefault ;
case 2 :
return theme . backgroundSecondary ;
case 3 :
return theme . backgroundTertiary ;
default :
return theme . backgroundRoot ;
}
};
Best Practices
Use elevation consistently
Maintain a consistent elevation hierarchy across your app: // Screen background: elevation 0
// Standard cards: elevation 1
// Nested cards: elevation 2
// Modals/overlays: elevation 3
Combine title and children thoughtfully
Use the title prop for simple headers, but use children for complex headers: // Simple
< Card title = "Settings" >
{ /* settings options */ }
</ Card >
// Complex
< Card >
< View style = { { flexDirection: 'row' , justifyContent: 'space-between' } } >
< ThemedText type = "h4" > Settings </ ThemedText >
< Icon name = "settings" />
</ View >
{ /* settings options */ }
</ Card >
Use onPress for navigation
Make cards interactive when they represent navigable items: < Card
title = "Workout Plan"
onPress = { () => navigation . navigate ( 'WorkoutDetail' ) }
>
< ThemedText > Tap to view details </ ThemedText >
</ Card >
Accessibility
When onPress is provided, the card becomes a pressable element
Title uses semantic heading typography (h4)
Description has reduced opacity for visual hierarchy
Animated feedback provides clear interaction cues
Source Code
Location: client/components/Card.tsx
The Card component is built using:
react-native-reanimated for press animations
ThemedText for title and description
useTheme hook for elevation-based backgrounds
Animated.createAnimatedComponent(Pressable) for interactive cards