A beautiful React Native animated button component with 3D press animation and haptic feedback
npm install react-native-3d-animated-buttonsbash
npm install react-native-3d-animated-buttons react-native-svg expo-haptics
`
That's it! Everything you need in one command to create Duolingo-style interactive buttons.
🚀 Quick Start
`tsx
import { AnimatedButton } from 'react-native-3d-animated-buttons';
title="Continue"
onPress={() => {}}
icon="apple"
type="capsule"
backgroundColor="#20B2AA"
shadowColor="#1A9B94"
/>
`
Usage
$3
`tsx
import React from 'react';
import { View } from 'react-native';
import { AnimatedButton } from 'react-native-3d-animated-buttons';
const App = () => {
return (
title="Press Me"
onPress={() => console.log('Button pressed!')}
/>
);
};
export default App;
`
$3
`tsx
import { AnimatedButton } from 'react-native-3d-animated-buttons';
title="Sign in with Apple"
onPress={() => handleAppleSignIn()}
backgroundColor="#000000"
shadowColor="#333333"
textColor="#FFFFFF"
hapticStyle="Medium"
icon="apple"
type="capsule"
loading={isLoading}
loadingText="Signing in..."
disabled={false}
fullWidth={true}
minHeight={60}
testID="apple-signin-button"
accessibilityLabel="Sign in with Apple account"
accessibilityHint="Double tap to sign in with your Apple ID"
onLongPress={() => showHelp()}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
style={{ marginBottom: 20 }}
textStyle={{ fontSize: 16, fontWeight: 'bold' }}
/>
`
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| title | string | Required | Button text |
| onPress | function | Required | Press handler function |
| backgroundColor | ColorValue | '#20B2AA' | Main button background color |
| shadowColor | ColorValue | '#1A9B94' | Shadow layer background color |
| textColor | ColorValue | '#FFFFFF' | Button text color |
| style | StyleProp | {} | Additional styles for button container |
| textStyle | StyleProp | {} | Additional styles for button text |
| disabled | boolean | false | Whether button is disabled |
| hapticStyle | HapticStyle | 'Heavy' | Haptic feedback style: 'Light', 'Medium', 'Heavy' |
| icon | IconType | null | Built-in icon type: 'apple', 'google', 'phone', 'facebook', or null |
| customIcon | IconComponent | null | Custom SVG icon component (highest priority) |
| customIconSvg | string | null | Custom SVG icon as string markup |
| iconSize | number | 24 | Icon size (width and height in pixels) |
| iconPosition | IconPosition | 'left' | Icon position: 'left' or 'right' (auto-swaps for RTL) |
| loading | boolean | false | Whether to show loading indicator |
| loadingText | string | null | Text to show when loading (optional) |
| type | ButtonType | 'normal' | Button type: 'normal' or 'capsule' |
| fullWidth | boolean | true | Whether button should take full width |
| minHeight | number | 52 | Minimum height of the button |
| testID | string | undefined | Test identifier for testing frameworks |
| accessibilityLabel | string | title | Accessibility label for screen readers |
| accessibilityHint | string | undefined | Accessibility hint (auto-sets to 'In progress' when loading) |
| onLongPress | function | undefined | Long press handler function |
| hitSlop | Insets | undefined | Touch target expansion for better accessibility |
| disableAnimations | boolean | false | Disable animations for accessibility (reduced motion) |
Examples
$3
`tsx
// Normal button
title="Normal Button"
onPress={() => {}}
type="normal"
/>
// Capsule button
title="Capsule Button"
onPress={() => {}}
type="capsule"
/>
`
$3
`tsx
// Apple Sign In
title="Sign in with Apple"
onPress={() => {}}
icon="apple"
backgroundColor="#000000"
shadowColor="#333333"
/>
// Google Sign In
title="Sign in with Google"
onPress={() => {}}
icon="google"
backgroundColor="#FFFFFF"
shadowColor="#E0E0E0"
textColor="#1A1A1A"
/>
// Facebook Sign In
title="Continue with Facebook"
onPress={() => {}}
icon="facebook"
backgroundColor="#1877F2"
shadowColor="#1464C7"
/>
// Phone Sign In
title="Sign in with Phone"
onPress={() => {}}
icon="phone"
backgroundColor="#34C759"
shadowColor="#2AA946"
/>
`
$3
`tsx
// Method 1: Custom React Component (Recommended)
import MyCustomIcon from './icons/MyCustomIcon';
title="Custom Icon Button"
onPress={() => {}}
customIcon={MyCustomIcon}
iconSize={24}
backgroundColor="#FF6B9D"
shadowColor="#E55A87"
/>
// Method 2: SVG String
title="SVG String Icon"
onPress={() => {}}
customIconSvg={}
iconSize={20}
backgroundColor="#FFD700"
shadowColor="#E6C200"
/>
// Method 3: Icon Priority (customIcon > customIconSvg > icon)
title="Priority Example"
onPress={() => {}}
icon="apple" // Ignored (lowest priority)
customIcon={HeartIcon} // Used (highest priority)
/>
// Method 4: Icon Positioning for Better UX
title="Previous"
onPress={() => {}}
customIconSvg={arrowLeftSvg}
iconPosition="left" // Arrow on left (default)
/>
title="Continue"
onPress={() => {}}
customIconSvg={arrowRightSvg}
iconPosition="right" // Arrow on right (better UX!)
/>
`
$3
`tsx
title="Submit"
onPress={() => {}}
loading={isSubmitting}
loadingText="Submitting..."
disabled={isSubmitting}
/>
`
$3
`tsx
title="Custom Button"
onPress={() => {}}
backgroundColor="#FF6B6B"
shadowColor="#E55555"
textColor="#FFFFFF"
style={{
marginHorizontal: 20,
marginBottom: 10
}}
textStyle={{
fontSize: 18,
fontWeight: '600'
}}
/>
`
$3
`tsx
title="Custom Font Button"
onPress={() => {}}
backgroundColor="#FF6B35"
shadowColor="#E55529"
textStyle={{
fontFamily: Platform.OS === 'ios' ? 'YourCustomFont-Bold' : 'your_custom_font_bold',
fontSize: 18,
fontWeight: '600',
letterSpacing: 0.5,
}}
/>
title="System Font"
onPress={() => {}}
textStyle={{
fontFamily: Platform.OS === 'ios' ? 'System' : 'Roboto',
fontSize: 16,
fontWeight: '500',
}}
/>
`
$3
`tsx
// Import icons from the comprehensive library
import { AnimatedButton, icons } from 'react-native-3d-animated-buttons';
// Social media icons
title="Sign in with Apple"
onPress={() => {}}
customIconSvg={icons.appleV1}
iconSize={20}
backgroundColor="#000000"
/>
// Payment icons
title="Add to Cart"
onPress={() => {}}
customIconSvg={icons.cartV1}
iconSize={18}
backgroundColor="#FF6B35"
/>
// Arrow icons with positioning
title="Continue"
onPress={() => {}}
customIconSvg={icons.arrowRightV1}
iconPosition="right"
backgroundColor="#34C759"
/>
// Common UI icons
title="Like Post"
onPress={() => {}}
customIconSvg={icons.heartV1}
iconSize={16}
backgroundColor="#FF6B9D"
/>
`
Advanced Features
$3
The component uses spring-based animations for a natural, responsive feel that mimics the satisfying button press experience found in apps like Duolingo:
`tsx
// Custom spring configuration (built-in)
title="Spring Button"
onPress={() => {}}
// Uses: stiffness: 300, damping: 20, mass: 0.4
/>
`
$3
Automatically detects and adapts to right-to-left languages:
`tsx
// Icon automatically swaps to right side in RTL languages
title="Continue"
icon="arrow-right"
// iconPosition not specified - auto-detects RTL
/>
`
$3
Enhanced accessibility with proper labels, hints, and touch targets:
`tsx
title="Accessible Button"
onPress={() => {}}
accessibilityLabel="Primary action button"
accessibilityHint="Double tap to perform the main action"
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
testID="primary-button"
/>
// Reduced motion support for accessibility
title="Static Button"
onPress={() => {}}
disableAnimations={true} // No animations for users who prefer reduced motion
/>
`
$3
Prevents accidental double-presses with configurable timing:
`tsx
title="Protected Button"
onPress={() => handleExpensiveOperation()}
// Automatically prevents rapid double-presses
/>
`
$3
Respects user accessibility preferences by allowing animation disabling:
`tsx
title="Accessible Button"
onPress={() => {}}
disableAnimations={true} // Respects user's reduced motion preference
/>
`
Haptic Feedback
The component uses Expo Haptics for tactile feedback. You can customize the intensity:
- 'Light' - Subtle feedback
- 'Medium' - Moderate feedback
- 'Heavy' - Strong feedback (default)
`tsx
title="Light Haptic"
onPress={() => {}}
hapticStyle="Light"
/>
`
TypeScript Support
This package is written in TypeScript and includes full type definitions. You'll get excellent IntelliSense support and type safety:
`tsx
import { AnimatedButton, AnimatedButtonProps, IconType, HapticStyle, ButtonType, IconPosition } from 'react-native-3d-animated-buttons';
// All props are fully typed
const MyButton: React.FC = () => {
const handlePress = (): void => {
console.log('Button pressed!');
};
return (
title="Typed Button"
onPress={handlePress}
hapticStyle="Medium" // Autocomplete available: 'Light' | 'Medium' | 'Heavy'
icon="apple" // Autocomplete available: 'apple' | 'google' | 'phone' | 'facebook'
type="capsule" // Autocomplete available: 'normal' | 'capsule'
iconPosition="right" // Autocomplete available: 'left' | 'right'
/>
);
};
`
Test App
This package includes a comprehensive test app demonstrating all features:
`bash
cd test-app
npm install
npx expo start
``