AnimatedCard
Card component with smooth press feedback and composable sub-components (CardHeader, CardTitle, CardDescription, CardContent, CardFooter) similar to shadcn/ui.
9:41
signal_cellular_altwifibattery_full
Create Project
Deploy your new project in one-click.
Project configuration goes here.
Preview Controls
Animation
Lift and shadow effect
This is a CSS-based preview of the animation. The actual React Native component uses physics-based springs for a more natural feel.
Installation
$
Usage
Example.tsx
import { AnimatedCard, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from './components/AnimatedCard';import { Button, Text } from 'react-native';export default function App() {return (<AnimatedCard onPress={() => console.log('Card pressed!')}><CardHeader><CardTitle>Create Project</CardTitle><CardDescription>Deploy your new project in one-click.</CardDescription></CardHeader><CardContent><Text>Your project configuration goes here.</Text></CardContent><CardFooter><Button title="Cancel" onPress={() => {}} /><Button title="Deploy" onPress={() => {}} /></CardFooter></AnimatedCard>);}
Full Component Code
AnimatedCard.tsx
1import React from 'react';2import { View, Text, ViewStyle, TextStyle, StyleProp, StyleSheet, TouchableWithoutFeedback } from 'react-native';3import Animated, { useSharedValue, useAnimatedStyle, withTiming, interpolate, Easing } from 'react-native-reanimated';45// AnimatedCard - Main card with press animations6export const AnimatedCard: React.FC<AnimatedCardProps> = ({7 children, onPress, style, pressScale = 0.98, duration = 150, elevation = 4, pressedElevation = 8,8}) => {9 const pressed = useSharedValue(0);10 const timingConfig = { duration, easing: Easing.out(Easing.ease) };1112 const animatedStyle = useAnimatedStyle(() => ({13 transform: [{ scale: interpolate(pressed.value, [0, 1], [1, pressScale]) }],14 shadowOpacity: interpolate(pressed.value, [0, 1], [0.15, 0.25]),15 elevation: interpolate(pressed.value, [0, 1], [elevation, pressedElevation]),16 }));1718 return (19 <TouchableWithoutFeedback onPress={onPress} onPressIn={() => pressed.value = withTiming(1, timingConfig)} onPressOut={() => pressed.value = withTiming(0, timingConfig)}>20 <Animated.View style={[styles.card, style, animatedStyle]}>{children}</Animated.View>21 </TouchableWithoutFeedback>22 );23};2425// Sub-components for composable structure26export const CardHeader = ({ children, style }) => <View style={[styles.header, style]}>{children}</View>;27export const CardTitle = ({ children, style }) => <Text style={[styles.title, style]}>{children}</Text>;28export const CardDescription = ({ children, style }) => <Text style={[styles.description, style]}>{children}</Text>;29export const CardContent = ({ children, style }) => <View style={[styles.content, style]}>{children}</View>;30export const CardFooter = ({ children, style }) => <View style={[styles.footer, style]}>{children}</View>;3132const styles = StyleSheet.create({33 card: { backgroundColor: '#fff', borderRadius: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowRadius: 8, overflow: 'hidden' },34 header: { padding: 16, paddingBottom: 8 },35 title: { fontSize: 18, fontWeight: '600', color: '#1a1a1a', marginBottom: 4 },36 description: { fontSize: 14, color: '#6b7280', lineHeight: 20 },37 content: { padding: 16, paddingTop: 0 },38 footer: { padding: 16, paddingTop: 8, flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', gap: 8, borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: '#e5e7eb' },39});
Props
| Name | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | - | Card content (use sub-components) |
| onPress | () => void | - | Optional press handler |
| pressScale | number | 0.98 | Scale when pressed |
| duration | number | 150 | Animation duration in ms |
| elevation | number | 4 | Default elevation |
| pressedElevation | number | 8 | Elevation when pressed |
