Skip to content

Card

Card provides a versatile container component with built-in theming, elevation support, and modular sub-components for headers, content, and footers. It supports multiple visual variants and responsive sizing options with platform-specific shadow handling.

import { Card, CardHeader, CardContent, CardFooter } from 'rnc-theme';
<Card>
<CardContent>
<Text>Basic card content</Text>
</CardContent>
</Card>
PropTypeDefaultDescription
variantComponentVariant'default'Visual style variant
sizeComponentSize'md'Card size (xs, sm, md, lg, xl)
disabledbooleanfalseDisable card interactions
paddingkeyof Theme['spacing']'md'Internal padding
marginkeyof Theme['spacing']-External margin
borderRadiuskeyof Theme['components']['borderRadius']'lg'Border radius value
elevationnumber3Shadow elevation (0 for no shadow)
shadowOpacitynumber0.1Shadow opacity value
backgroundColorstring-Custom background color
PropTypeDefaultDescription
titlestring-Header title text
subtitlestring-Header subtitle text
paddingkeyof Theme['spacing']'sm'Header padding
titleVariantkeyof Theme['typography']'subtitle'Title typography variant
subtitleVariantkeyof Theme['typography']'body'Subtitle typography variant
borderBottombooleanfalseShow bottom border
titleStyleTextStyle-Custom title styles
subtitleStyleTextStyle-Custom subtitle styles
PropTypeDefaultDescription
paddingkeyof Theme['spacing']'sm'Content padding
styleViewStyle-Additional content styles
PropTypeDefaultDescription
paddingkeyof Theme['spacing']'sm'Footer padding
showBorderbooleanfalseShow top border
justifyViewStyle['justifyContent']'flex-end'Content justification
styleViewStyle-Additional footer styles
VariantDescriptionUse Case
defaultStandard card appearanceGeneral content containers
primaryPrimary branded cardImportant content, featured items
secondarySecondary styled cardSupporting content
outlineOutlined transparent cardSubtle containers, form sections
ghostMinimal transparent cardSubtle grouping without visual weight
filledFilled background cardContent differentiation
successSuccess state cardPositive feedback, confirmations
errorError state cardError messages, warnings
warningWarning state cardCaution notices
infoInformation cardTips, help content
destructiveDestructive action cardDelete confirmations, critical actions
<VStack spacing="lg" padding="lg">
<Card variant="info">
<CardHeader
title="Tip"
subtitle="Improve your workflow"
borderBottom
/>
<CardContent>
<Text>
Use keyboard shortcuts to navigate faster through the application.
Press Ctrl+K to open the command palette.
</Text>
</CardContent>
</Card>
<Card variant="warning">
<CardHeader title="Storage Warning" />
<CardContent>
<Text>
You're running low on storage space. Consider deleting old files
or upgrading your plan.
</Text>
</CardContent>
<CardFooter>
<Button variant="outline" size="sm">Learn More</Button>
</CardFooter>
</Card>
</VStack>
<Card variant="default" elevation={4}>
<CardHeader
title="John Doe"
subtitle="Software Engineer"
borderBottom
/>
<CardContent>
<VStack spacing="md">
<HStack spacing="md" align="center">
<Icon name="email" />
<Text>john.doe@example.com</Text>
</HStack>
<HStack spacing="md" align="center">
<Icon name="phone" />
<Text>+1 (555) 123-4567</Text>
</HStack>
<HStack spacing="md" align="center">
<Icon name="location" />
<Text>San Francisco, CA</Text>
</HStack>
</VStack>
</CardContent>
<CardFooter showBorder justify="space-between">
<Button variant="outline">Message</Button>
<Button variant="primary">Connect</Button>
</CardFooter>
</Card>
<HStack spacing="lg" wrap>
<Card variant="success" size="sm" style={{ minWidth: 200 }}>
<CardContent>
<VStack spacing="sm">
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'white' }}>
2,543
</Text>
<Text style={{ color: 'rgba(255,255,255,0.8)' }}>
Total Sales
</Text>
</VStack>
</CardContent>
</Card>
<Card variant="primary" size="sm" style={{ minWidth: 200 }}>
<CardContent>
<VStack spacing="sm">
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'white' }}>
342
</Text>
<Text style={{ color: 'rgba(255,255,255,0.8)' }}>
New Customers
</Text>
</VStack>
</CardContent>
</Card>
<Card variant="warning" size="sm" style={{ minWidth: 200 }}>
<CardContent>
<VStack spacing="sm">
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'white' }}>
23
</Text>
<Text style={{ color: 'rgba(255,255,255,0.8)' }}>
Pending Orders
</Text>
</VStack>
</CardContent>
</Card>
</HStack>
const ProductCard = ({ product }) => (
<Card variant="outline" elevation={2}>
<CardContent padding="none">
<Image
source={{ uri: product.image }}
style={{ width: '100%', height: 200, borderRadius: 8 }}
/>
</CardContent>
<CardContent>
<VStack spacing="sm">
<Text style={{ fontSize: 18, fontWeight: '600' }}>
{product.name}
</Text>
<Text style={{ color: '#666' }}>
{product.description}
</Text>
<HStack justify="space-between" align="center">
<Text style={{ fontSize: 20, fontWeight: 'bold', color: '#007AFF' }}>
${product.price}
</Text>
<HStack spacing="xs" align="center">
<Icon name="star" color="#FFD700" />
<Text>{product.rating}</Text>
</HStack>
</HStack>
</VStack>
</CardContent>
<CardFooter>
<Button variant="primary" fullWidth>
Add to Cart
</Button>
</CardFooter>
</Card>
);
<VStack spacing="md">
<Card variant="default">
<CardHeader
title="Account Settings"
subtitle="Manage your account preferences"
borderBottom
/>
<CardContent>
<VStack spacing="lg">
<HStack justify="space-between" align="center">
<VStack>
<Text style={{ fontWeight: '600' }}>Email Notifications</Text>
<Text style={{ color: '#666', fontSize: 14 }}>
Receive updates via email
</Text>
</VStack>
<Switch value={emailNotifications} onValueChange={setEmailNotifications} />
</HStack>
<HStack justify="space-between" align="center">
<VStack>
<Text style={{ fontWeight: '600' }}>Two-Factor Authentication</Text>
<Text style={{ color: '#666', fontSize: 14 }}>
Add an extra layer of security
</Text>
</VStack>
<Switch value={twoFactor} onValueChange={setTwoFactor} />
</HStack>
</VStack>
</CardContent>
</Card>
<Card variant="error">
<CardHeader title="Danger Zone" />
<CardContent>
<Text style={{ color: 'white', marginBottom: 16 }}>
These actions cannot be undone. Please proceed with caution.
</Text>
</CardContent>
<CardFooter>
<Button variant="destructive">
Delete Account
</Button>
</CardFooter>
</Card>
</VStack>
const ContactForm = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
return (
<Card variant="default" elevation={3}>
<CardHeader
title="Contact Us"
subtitle="We'd love to hear from you"
borderBottom
/>
<CardContent>
<VStack spacing="lg">
<VStack spacing="sm">
<Text style={{ fontWeight: '600' }}>Name</Text>
<TextInput
value={formData.name}
onChangeText={(name) => setFormData(prev => ({ ...prev, name }))}
placeholder="Enter your name"
/>
</VStack>
<VStack spacing="sm">
<Text style={{ fontWeight: '600' }}>Email</Text>
<TextInput
value={formData.email}
onChangeText={(email) => setFormData(prev => ({ ...prev, email }))}
placeholder="Enter your email"
keyboardType="email-address"
/>
</VStack>
<VStack spacing="sm">
<Text style={{ fontWeight: '600' }}>Message</Text>
<TextInput
value={formData.message}
onChangeText={(message) => setFormData(prev => ({ ...prev, message }))}
placeholder="Enter your message"
multiline
numberOfLines={4}
/>
</VStack>
</VStack>
</CardContent>
<CardFooter showBorder justify="space-between">
<Button variant="outline" onPress={handleReset}>
Reset
</Button>
<Button variant="primary" onPress={handleSubmit}>
Send Message
</Button>
</CardFooter>
</Card>
);
};
<Card variant="default" elevation={4}>
<CardHeader title="Project Overview" borderBottom />
<CardContent>
<VStack spacing="md">
<Text>Main project information and statistics</Text>
<Card variant="ghost" elevation={0}>
<CardHeader title="Team Members" />
<CardContent>
<Text>Nested card for team information</Text>
</CardContent>
</Card>
<Card variant="outline" elevation={1}>
<CardHeader title="Recent Activity" />
<CardContent>
<Text>Another nested card for activity feed</Text>
</CardContent>
</Card>
</VStack>
</CardContent>
</Card>
const StatusCard = ({ status, data }) => {
const getVariant = () => {
switch (status) {
case 'loading': return 'default';
case 'success': return 'success';
case 'error': return 'error';
case 'warning': return 'warning';
default: return 'default';
}
};
const getContent = () => {
switch (status) {
case 'loading':
return (
<CardContent>
<HStack spacing="md" align="center">
<ActivityIndicator />
<Text>Loading data...</Text>
</HStack>
</CardContent>
);
case 'success':
return (
<>
<CardHeader title="Success!" />
<CardContent>
<Text style={{ color: 'white' }}>{data.message}</Text>
</CardContent>
</>
);
case 'error':
return (
<>
<CardHeader title="Error" />
<CardContent>
<Text style={{ color: 'white' }}>{data.error}</Text>
</CardContent>
<CardFooter>
<Button variant="outline" onPress={data.onRetry}>
Retry
</Button>
</CardFooter>
</>
);
default:
return (
<CardContent>
<Text>Default content</Text>
</CardContent>
);
}
};
return (
<Card variant={getVariant()} elevation={status === 'loading' ? 1 : 3}>
{getContent()}
</Card>
);
};
const CardGrid = ({ items }) => {
const screenWidth = Dimensions.get('window').width;
const cardWidth = screenWidth > 768 ? (screenWidth - 48) / 3 : screenWidth - 32;
return (
<ScrollView contentContainerStyle={{ padding: 16 }}>
<View style={{
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between'
}}>
{items.map((item, index) => (
<Card
key={index}
variant="outline"
style={{
width: cardWidth,
marginBottom: 16
}}
>
<CardHeader title={item.title} />
<CardContent>
<Text>{item.description}</Text>
</CardContent>
</Card>
))}
</View>
</ScrollView>
);
};
<Card size="xs" variant="primary">
<CardContent>
<Text>Extra small card</Text>
</CardContent>
</Card>

Content Organization

  • Use CardHeader for titles and navigation elements
  • Keep CardContent focused on the main information
  • Place actions in CardFooter for better user experience
  • Maintain consistent padding across card sections

Visual Hierarchy

  • Use elevation to establish depth and importance
  • Choose variants that match content purpose and urgency
  • Maintain consistent spacing between cards in lists
  • Consider disabled state for temporary unavailable content

Performance

  • Use appropriate elevation values to avoid excessive shadows
  • Consider using ghost variant for minimal visual impact
  • Implement virtualization for long lists of cards
  • Optimize images and content within cards for smooth scrolling

Platform Considerations

  • Elevation automatically uses box-shadow on web platforms
  • Test shadow appearance across different devices
  • Consider reduced motion preferences for accessibility
  • Ensure sufficient contrast in all variant combinations