Back to Components

Morphing Button

Essential comps
7 months ago

About

AnimatedButton

A sophisticated animated button component for React Native that provides smooth state transitions with loading, success, and error states.

Features

  • 🎨 Smooth Animations: Fade and slide transitions between states
  • πŸ”„ Async Support: Works seamlessly with real API calls
  • πŸ›‘οΈ Error Handling: Automatic error state management
  • βš™οΈ Highly Configurable: Customizable animations and states
  • πŸ“± Responsive: Maintains consistent height during state changes
  • 🎯 Type Safe: Full TypeScript support

Basic Usage

tsx
import React from 'react'; import { AnimatedButton } from '../components/animated-button'; export default function MyComponent() { const handleSave = async () => { // Your API call here await fetch('/api/save', { method: 'POST' }); }; return ( <AnimatedButton title="Save Changes" onPress={handleSave} variant="primary" size="medium" fullWidth /> ); }

Props

Core Props

PropTypeDefaultDescription
titlestring-Button text to display
onPress() => Promise<void> | void-Async function to execute
variant'primary' | 'secondary' | 'outline' | 'ghost' | 'danger''primary'Button style variant
size'small' | 'medium' | 'large''medium'Button size
disabledbooleanfalseDisable button interaction
fullWidthbooleanfalseMake button full width
styleViewStyle-Custom button styles
textStyleTextStyle-Custom text styles
leftIconReact.ReactNode-Icon to display on the left
rightIconReact.ReactNode-Icon to display on the right

Animation Configuration

PropTypeDefaultDescription
animationConfig.durationnumber150Animation duration in ms
animationConfig.delaynumber150Delay before new content appears
animationConfig.translateDistancenumber25Distance for translate animation

State Configuration

PropTypeDefaultDescription
stateConfig.successDurationnumber3500How long to show success state
stateConfig.loadingTextReact.ReactNodenullCustom loading content (or spinner)
stateConfig.successTextstring'Login link sent!'Success message
stateConfig.errorTextstring'Something went wrong'Error message

Button States

The button automatically manages these states:

  1. Idle β†’ Loading β†’ Success β†’ Idle
  2. Idle β†’ Loading β†’ Error β†’ Idle

State Flow

tsx
// 1. User presses button // 2. Button shows loading state with spinner // 3. API call executes // 4. On success: Shows success message for 3.5s, then returns to idle // 5. On error: Shows error message for 3.5s, then returns to idle

Variants

Primary (Default)

tsx
<AnimatedButton title="Save" onPress={handleSave} variant="primary" />

Secondary

tsx
<AnimatedButton title="Cancel" onPress={handleCancel} variant="secondary" />

Outline

tsx
<AnimatedButton title="Edit" onPress={handleEdit} variant="outline" />

Ghost

tsx
<AnimatedButton title="Delete" onPress={handleDelete} variant="ghost" />

Danger

tsx
<AnimatedButton title="Delete Account" onPress={handleDeleteAccount} variant="danger" />

Sizes

Small

tsx
<AnimatedButton title="Save" onPress={handleSave} size="small" />

Medium (Default)

tsx
<AnimatedButton title="Save" onPress={handleSave} size="medium" />

Large

tsx
<AnimatedButton title="Save" onPress={handleSave} size="large" />

Advanced Examples

Custom Animation Speed

tsx
<AnimatedButton title="Quick Save" onPress={handleQuickSave} animationConfig={{ duration: 100, delay: 100, translateDistance: 30, }} />

Custom State Messages

tsx
<AnimatedButton title="Delete User" onPress={handleDeleteUser} variant="danger" stateConfig={{ loadingText: 'Deleting...', successText: 'User deleted!', errorText: 'Failed to delete user', }} />

Custom Loading Content

tsx
<AnimatedButton title="Process Data" onPress={handleProcessData} stateConfig={{ loadingText: ( <View style={{ flexDirection: 'row', alignItems: 'center' }}> <ActivityIndicator size="small" color="#fff" /> <Text style={{ color: '#fff', marginLeft: 8 }}>Processing...</Text> </View> ), }} />

Form Validation

tsx
const handleSave = async () => { if (!email || !password) { throw new Error('Please fill in all fields'); } await saveUser({ email, password }); }; <AnimatedButton title="Save" onPress={handleSave} stateConfig={{ errorText: 'Please fill in all fields', }} />

Real API Integration

tsx
const handleLogin = async () => { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); if (!response.ok) { throw new Error('Login failed'); } return response.json(); }; <AnimatedButton title="Sign In" onPress={handleLogin} stateConfig={{ successText: 'Welcome back!', errorText: 'Invalid credentials', }} />

Best Practices

1. Always Handle Errors

tsx
const handleSave = async () => { try { await saveData(); } catch (error) { // The button will automatically show error state throw error; } };

2. Use Appropriate Variants

  • Primary: Main actions (Save, Submit, Confirm)
  • Secondary: Secondary actions (Cancel, Back)
  • Outline: Alternative actions (Edit, View)
  • Ghost: Subtle actions (More, Details)
  • Danger: Destructive actions (Delete, Remove)

3. Customize Messages for Context

tsx
// Login form stateConfig={{ successText: 'Welcome back!', errorText: 'Invalid credentials', }} // Save form stateConfig={{ successText: 'Changes saved!', errorText: 'Failed to save changes', }} // Delete action stateConfig={{ loadingText: 'Deleting...', successText: 'Item deleted!', errorText: 'Failed to delete item', }}

4. Optimize Animation Performance

tsx
// For fast operations animationConfig={{ duration: 100, delay: 100, }} // For slower operations animationConfig={{ duration: 200, delay: 200, }}

Dependencies

  • react-native-reanimated: For smooth animations
  • react-native: Core React Native components
  • @expo/vector-icons: For default icons (optional)

License

Feel free to use in your projects after purchasing the pro!

Posted by

E

eren

@eren