Free
Open source • Copy & paste

DeFi Wallet

Crypto dashboard kit

Portfolio overview, asset list, and market cards for fintech products.

5 screens
Expo Router + StyleSheet + Reanimated + SVG
Motion-ready
walletportfoliomarketcrypto
Browse more kits

Source code

Explore the component structure. Copy directly into any Expo app.

import { Ionicons } from '@expo/vector-icons';
import { Stack, useRouter } from 'expo-router';
import React from 'react';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import Animated, {
  FadeInUp,
  useAnimatedScrollHandler,
  useSharedValue,
} from 'react-native-reanimated';

import { FocusAwareStatusBar, Text } from '@/components/ui';

import { ActionButtons } from '../components/ActionButtons';
import { AssetRow } from '../components/AssetRow';
import { BalanceCard } from '../components/BalanceCard';
import { FINANCE_COLORS, MOCK_ASSETS } from '../constants';

export default function WalletDashboard() {
  const router = useRouter();
  const scrollY = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler((event) => {
    scrollY.value = event.contentOffset.y;
  });

  return (
    <View style={styles.container}>
      <FocusAwareStatusBar barStyle="light-content" />
      <Stack.Screen options={{ headerShown: false }} />

      {/* Custom Header */}
      <View style={styles.header}>
        <View style={styles.profileSection}>
          <View style={styles.avatar}>
            <Text style={styles.avatarText}>MZ</Text>
          </View>
          <View>
            <Text style={styles.greetingLabel}>Good Morning</Text>
            <Text style={styles.greetingName}>Muhammad</Text>
          </View>
        </View>
        <TouchableOpacity
          onPress={() =>
            router.push('/(root)/(protected)/screen-kits/finance/notifications')
          }
          style={styles.notificationButton}
        >
          <View style={styles.notificationDot} />
          <Ionicons name="notifications-outline" size={20} color="white" />
        </TouchableOpacity>
      </View>

      <Animated.ScrollView
        onScroll={scrollHandler}
        scrollEventThrottle={16}
        contentContainerStyle={styles.scrollContent}
        style={styles.scrollView}
      >
        <BalanceCard />

        <ActionButtons
          onSendBy={() =>
            router.push('/(root)/(protected)/screen-kits/finance/send')
          }
          onReceive={() =>
            router.push('/(root)/(protected)/screen-kits/finance/receive')
          }
          onSwap={() =>
            router.push('/(root)/(protected)/screen-kits/finance/swap')
          }
          onBuy={() =>
            router.push('/(root)/(protected)/screen-kits/finance/asset-detail')
          }
        />

        <View style={styles.assetsSection}>
          <View style={styles.assetsSectionHeader}>
            <Text style={styles.assetsSectionTitle}>Your Assets</Text>
            <TouchableOpacity>
              <Text style={styles.seeAllText}>See All</Text>
            </TouchableOpacity>
          </View>

          <View style={styles.assetsList}>
            {MOCK_ASSETS.map((asset, index) => (
              <Animated.View
                key={asset.id}
                entering={FadeInUp.delay(400 + index * 100).springify()}
              >
                <AssetRow
                  asset={asset}
                  onPress={() =>
                    router.push({
                      pathname:
                        '/(root)/(protected)/screen-kits/finance/asset-detail',
                      params: {
                        ...asset,
                        chartData: JSON.stringify(asset.chartData),
                      },
                    })
                  }
                />
              </Animated.View>
            ))}
          </View>
        </View>

        {/* Promo / News Card (Horizontal Scroll) */}
        <Text style={styles.marketUpdatesTitle}>Market Updates</Text>
        <Animated.ScrollView
          horizontal
          showsHorizontalScrollIndicator={false}
          style={styles.horizontalScroll}
          contentContainerStyle={styles.horizontalScrollContent}
        >
          {[1, 2, 3].map((i) => (
            <View key={i} style={styles.newsCard}>
              <View style={styles.newsCardHeader}>
                <View style={styles.newsBadge}>
                  <Text style={styles.newsBadgeText}>CRYPTO NEWS</Text>
                </View>
                <Text style={styles.newsTime}>2h ago</Text>
              </View>
              <Text style={styles.newsHeadline}>
                Bitcoin surges past $28k following new ETF approval rumors.
              </Text>
            </View>
          ))}
        </Animated.ScrollView>
      </Animated.ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: FINANCE_COLORS.background,
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingHorizontal: 24,
    paddingTop: 56,
    paddingBottom: 16,
    backgroundColor: 'rgba(9, 9, 11, 0.8)',
    zIndex: 10,
  },
  profileSection: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 12,
  },
  avatar: {
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: '#27272a',
    alignItems: 'center',
    justifyContent: 'center',
    borderWidth: 1,
    borderColor: '#3f3f46',
  },
  avatarText: {
    fontWeight: '700',
    fontSize: 18,
    color: '#ffffff',
  },
  greetingLabel: {
    color: '#a1a1aa',
    fontSize: 12,
    textTransform: 'uppercase',
    letterSpacing: 1,
    fontWeight: '700',
  },
  greetingName: {
    color: '#ffffff',
    fontWeight: '700',
    fontSize: 18,
  },
  notificationButton: {
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: '#18181b',
    alignItems: 'center',
    justifyContent: 'center',
    borderWidth: 1,
    borderColor: '#27272a',
  },
  notificationDot: {
    position: 'absolute',
    top: 8,
    right: 10,
    width: 8,
    height: 8,
    borderRadius: 4,
    backgroundColor: '#ef4444',
    zIndex: 10,
    borderWidth: 1,
    borderColor: '#18181b',
  },
  scrollView: {
    flex: 1,
    paddingHorizontal: 24,
  },
  scrollContent: {
    paddingBottom: 100,
  },
  assetsSection: {
    marginBottom: 24,
  },
  assetsSectionHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    marginBottom: 16,
  },
  assetsSectionTitle: {
    fontSize: 20,
    fontWeight: '700',
    color: '#ffffff',
  },
  seeAllText: {
    color: '#71717a',
    fontSize: 14,
    fontWeight: '500',
  },
  assetsList: {
    gap: 8,
  },
  marketUpdatesTitle: {
    fontSize: 20,
    fontWeight: '700',
    color: '#ffffff',
    marginBottom: 16,
  },
  horizontalScroll: {
    marginHorizontal: -24,
  },
  horizontalScrollContent: {
    paddingHorizontal: 24,
  },
  newsCard: {
    width: 256,
    height: 128,
    borderRadius: 16,
    backgroundColor: '#18181b',
    borderWidth: 1,
    borderColor: '#27272a',
    marginRight: 16,
    padding: 16,
    justifyContent: 'space-between',
  },
  newsCardHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  newsBadge: {
    backgroundColor: 'rgba(139, 92, 246, 0.2)',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 6,
    alignSelf: 'flex-start',
  },
  newsBadgeText: {
    color: '#a78bfa',
    fontSize: 10,
    fontWeight: '700',
  },
  newsTime: {
    color: '#71717a',
    fontSize: 12,
  },
  newsHeadline: {
    color: '#ffffff',
    fontWeight: '700',
    lineHeight: 20,
  },
});

Building a full app?

VibeFast Pro is a complete Expo + Next.js starter kit with authentication, payments (RevenueCat), AI features, backend (Convex/Supabase), and more. Ship your app in days, not months.

Learn more