FinPanel
An edge-swipe quick actions drawer with a second swappable insights page and staggered entrance animations.
Edge pill trigger
Tap or swipe left on the right-edge pill to open; it fades out the instant the drawer appears.
Two-page swipeable drawer
Quick Actions and Insights sit side by side in one carousel, with an animated pill-dot indicator tracking the active page.
Staggered entrance animations
Each action springs and fades in with a per-index delay, driven by a reusable animation primitive.
Independent, non-conflicting gestures
Pill tap/swipe, drawer paging, and overlay tap-to-dismiss are separate gesture recognizers, so none of them fight.
Installation
Copy the command directly into your project.
Install the needed dependencies
Use in your app
Built to match the preview exactly — for the complete implementation, check the repo on GitHub.
import { StyleSheet, View } from 'react-native'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import QuickActionsDrawer from '../../components/fin-panel/components/QuickActionsDrawer'
export default function Index() {
return (
<GestureHandlerRootView style={styles.root}>
<View style={styles.container}>
<QuickActionsDrawer />
</View>
</GestureHandlerRootView>
)
}
const styles = StyleSheet.create({
root: {
flex: 1,
},
container: {
flex: 1,
backgroundColor: '#000000',
},
})API
<QuickActionsDrawer>
| Prop | Type | Default | Description |
|---|---|---|---|
| actions | readonly ActionItem[] | 5 built-in fintech actions (Cards, Quick Pay, Savings, Crypto, Your Bills) | Actions rendered in the grid on page one. |
| onActionPress | (actionId: string) => void | — | Called when an action is tapped. The drawer closes automatically before this fires. |
| onOpenChange | (isOpen: boolean) => void | — | Called whenever the drawer opens or closes, whether by gesture or overlay tap. |
<ActionPanel>
| Prop | Type | Default | Description |
|---|---|---|---|
| actions | readonly ActionItem[] | — | Actions to render in the grid. |
| visible | boolean | — | Controls the stagger entrance animation. |
| onActionPress | (id: string) => void | — | Fired on tap. |
| width | number | — | Panel width — driven by the parent drawer's page width. |
<InsightPanel>
| Prop | Type | Default | Description |
|---|---|---|---|
| visible | boolean | — | Controls the entrance animation. |
| width | number | — | Panel width — driven by the parent drawer. |
Ships as a placeholder — swap it for your own content (spending stats, subscriptions, a savings streak, etc.), and wrap it in AnimatedStaggerItem to keep the same entrance motion as the rest of the drawer.
<AnimatedStaggerItem>
| Prop | Type | Default | Description |
|---|---|---|---|
| index | number | — | Position in the stagger sequence. |
| visible | boolean | — | Triggers entrance (true) or resets (false). |
| baseDelay | number | 80 | ms before the first item starts entering. |
| staggerMs | number | 60 | ms added per subsequent index. |
| translateDistance | number | 40 | px the item translates in from. |
| springConfig | WithSpringConfig | { damping: 18, stiffness: 220, mass: 0.6 } | Spring driving the translate. |
| fadeConfig | WithTimingConfig | { duration: 180 } | Timing driving the opacity fade. |
| children | ReactNode | — | Content to animate in. |
Gestures
| Gesture | Result |
|---|---|
| Tap or swipe left on the edge pill | Opens the drawer |
| Swipe left on the drawer | Advances from Quick Actions → Insights |
| Swipe right on Insights | Goes back to Quick Actions |
| Swipe right on Quick Actions | Closes the drawer |
| Tap the overlay | Closes the drawer from any page |
Types
interface ActionItem {
readonly id: string;
readonly label: string;
readonly icon: ImageSourcePropType;
}
type DrawerPage = 'actions' | 'insights';