logoChisa UI

Command Palette

Search for a command to run...

Componentschevron_rightAnimatedCard

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';
4
5// AnimatedCard - Main card with press animations
6export 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) };
11
12 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 }));
17
18 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};
24
25// Sub-components for composable structure
26export 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>;
31
32const 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

NameTypeDefaultDescription
childrenReact.ReactNode-Card content (use sub-components)
onPress() => void-Optional press handler
pressScalenumber0.98Scale when pressed
durationnumber150Animation duration in ms
elevationnumber4Default elevation
pressedElevationnumber8Elevation when pressed