logoChisa UI

Command Palette

Search for a command to run...

Componentschevron_rightAnimatedButton

AnimatedButton

Button with smooth press feedback using timing-based animations.

9:41
signal_cellular_altwifibattery_full

Preview Controls

Animation

Press and release

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 { AnimatedButton } from './components/AnimatedButton';
export default function App() {
return (
<AnimatedButton onPress={() => console.log('Pressed!')}>
Press Me
</AnimatedButton>
);
}

Full Component Code

AnimatedButton.tsx
1import React from 'react';
2import {
3 TouchableWithoutFeedback,
4 ViewStyle,
5 StyleProp,
6 TextStyle,
7 StyleSheet,
8 Text,
9} from 'react-native';
10import Animated, {
11 useSharedValue,
12 useAnimatedStyle,
13 withTiming,
14 interpolateColor,
15 Easing,
16} from 'react-native-reanimated';
17
18interface AnimatedButtonProps {
19 onPress?: () => void;
20 children: React.ReactNode;
21 style?: StyleProp<ViewStyle>;
22 textStyle?: StyleProp<TextStyle>;
23 pressScale?: number;
24 duration?: number;
25 backgroundColor?: string;
26 pressedBackgroundColor?: string;
27 textColor?: string;
28 disabled?: boolean;
29}
30
31export const AnimatedButton: React.FC<AnimatedButtonProps> = ({
32 onPress,
33 children,
34 style,
35 textStyle,
36 pressScale = 0.95,
37 duration = 150,
38 backgroundColor = '#c43b15',
39 pressedBackgroundColor = '#c4320a',
40 textColor = '#ffffff',
41 disabled = false,
42}) => {
43 const scale = useSharedValue(1);
44 const pressed = useSharedValue(0);
45
46 const timingConfig = {
47 duration,
48 easing: Easing.out(Easing.ease),
49 };
50
51 const handlePressIn = () => {
52 scale.value = withTiming(pressScale, timingConfig);
53 pressed.value = withTiming(1, timingConfig);
54 };
55
56 const handlePressOut = () => {
57 scale.value = withTiming(1, timingConfig);
58 pressed.value = withTiming(0, timingConfig);
59 };
60
61 const animatedStyle = useAnimatedStyle(() => ({
62 transform: [{ scale: scale.value }],
63 backgroundColor: interpolateColor(
64 pressed.value,
65 [0, 1],
66 [backgroundColor, pressedBackgroundColor]
67 ),
68 }));
69
70 const renderChildren = () => {
71 if (typeof children === 'string' || typeof children === 'number') {
72 return (
73 <Text style={[styles.text, { color: textColor }, textStyle]}>
74 {children}
75 </Text>
76 );
77 }
78 return children;
79 };
80
81 return (
82 <TouchableWithoutFeedback
83 onPress={onPress}
84 onPressIn={handlePressIn}
85 onPressOut={handlePressOut}
86 disabled={disabled}
87 >
88 <Animated.View style={[styles.button, style, animatedStyle, disabled && styles.disabled]}>
89 {renderChildren()}
90 </Animated.View>
91 </TouchableWithoutFeedback>
92 );
93};
94
95const styles = StyleSheet.create({
96 button: {
97 paddingVertical: 14,
98 paddingHorizontal: 28,
99 borderRadius: 12,
100 alignItems: 'center',
101 justifyContent: 'center',
102 },
103 text: {
104 fontSize: 16,
105 fontWeight: '600',
106 },
107 disabled: {
108 opacity: 0.5,
109 },
110});
111
112export default AnimatedButton;

Props

NameTypeDefaultDescription
childrenReact.ReactNode-Button content (auto-wraps strings in Text)
onPress() => void-Press handler
pressScalenumber0.95Scale when pressed
durationnumber150Animation duration in ms
backgroundColorstring'#c43b15'Default background color
pressedBackgroundColorstring'#c4320a'Background when pressed
textColorstring'#ffffff'Text color for string children
disabledbooleanfalseDisable the button