Profile Pic

A profile picture component with fallback, loading state, and customizable styling

Profile Pic Component Example

Installation

npx expo-app-ui add profile-pic

:::note The profile pic component is self-contained and doesn’t require any external dependencies. It uses expo-image for optimized image loading. :::

Usage

import ProfilePic from "@/components/ui/profile-pic";
 
<ProfilePic source="https://example.com/avatar.jpg" username="John Doe" />

Complete Example

Here’s a complete example showing all profile pic features:

import CustomText from "@/components/ui/custom-text";
import ProfilePic from "@/components/ui/profile-pic";
import React, { useState } from "react";
import { StyleSheet, TouchableOpacity, View } from "react-native";
 
export default function Index() {
  const [loading, setLoading] = useState(false);
  const toggleLoading = () => {
    setLoading(true);
    setTimeout(() => setLoading(false), 10000);
  };
 
  return (
    <View style={styles.container}>
      <CustomText fontSize={28} style={styles.title}>
        Profile Picture Examples
      </CustomText>
 
      {/* Default avatar with image */}
      <View style={styles.row}>
        <ProfilePic source="john.png" username="John" />
        <CustomText style={styles.label}>With Image</CustomText>
      </View>
 
      {/* No image → fallback initial */}
      <View style={styles.row}>
        <ProfilePic username="Alice" backgroundColor="black" />
        <CustomText style={styles.label}>Fallback Initial</CustomText>
      </View>
 
      {/* Custom size & border */}
      <View style={styles.row}>
        <ProfilePic
          username="Michael"
          width={80}
          height={80}
          borderWidth={2}
          borderColor="#175676"
          backgroundColor="#175676"
        />
        <CustomText style={styles.label}>Custom Size</CustomText>
      </View>
 
      {/* Loading state */}
      <View style={styles.row}>
        <ProfilePic
          username="Loading"
          width={70}
          height={70}
          isLoading={loading}
        />
        <CustomText style={styles.label}>Loading State</CustomText>
      </View>
 
      {/* Toggle loading */}
      <TouchableOpacity style={styles.button} onPress={toggleLoading}>
        <CustomText color="white">Toggle Loading</CustomText>
      </TouchableOpacity>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    paddingHorizontal: 24,
    backgroundColor: "#FFFFFF",
  },
  title: {
    textAlign: "center",
    marginBottom: 40,
  },
  row: {
    flexDirection: "row",
    alignItems: "center",
    marginBottom: 20,
    gap: 16,
  },
  label: {
    fontSize: 16,
    color: "#333",
  },
  button: {
    marginTop: 30,
    backgroundColor: "#007AFF",
    paddingVertical: 14,
    borderRadius: 10,
    alignItems: "center",
  },
});

Props

PropTypeDefaultDescription
sourcestring-Image URL or path. If not provided, shows fallback initial
usernamestringRequiredUsername for fallback initials (first letter will be displayed)
widthnumber50Image width
heightnumber50Image height
borderRadiusnumber50Border radius (50 = circle)
borderWidthnumber1Border width
borderColorstring"#FFFFFF"Border color
backgroundColorstring"#000000"Background color for fallback initial
isLoadingbooleanfalseShow loading indicator
styleStyleProp<ViewStyle>-Custom container styles

Examples

With Image

<ProfilePic source="https://example.com/avatar.jpg" username="John Doe" />

Fallback to Initials

When no image is provided, the component automatically shows the first letter of the username:

<ProfilePic username="Jane Smith" />

Custom Size

<ProfilePic
  username="Michael"
  width={80}
  height={80}
  borderRadius={40}
/>

Custom Border

<ProfilePic
  username="Alice"
  width={60}
  height={60}
  borderWidth={3}
  borderColor="#007AFF"
  backgroundColor="#007AFF"
/>

Loading State

<ProfilePic
  username="Loading"
  width={70}
  height={70}
  isLoading={true}
/>

Circle Avatar

{/* Default is circle (borderRadius: 50) */}
<ProfilePic username="John" width={50} height={50} />
 
{/* Square avatar */}
<ProfilePic username="John" width={50} height={50} borderRadius={10} />

With Environment Variable URL

The component supports EXPO_PUBLIC_API_URL for image paths:

{/* If EXPO_PUBLIC_API_URL is set, image will be loaded from: */}
{/* ${EXPO_PUBLIC_API_URL}/avatar/john.png */}
<ProfilePic source="john.png" username="John" />

Features

  • Automatic Fallback: Shows user initial when image is not available
  • Loading State: Built-in loading indicator
  • Optimized Images: Uses expo-image for better performance and blurhash support
  • Customizable: Full control over size, border, colors, and styling
  • Blurhash Placeholder: Supports blurhash for smooth image loading
  • No Dependencies: Self-contained component (only requires expo-image)
  • Flexible Sizing: Support for any width/height combination
  • Border Support: Customizable border width and color

Notes

  • The component uses expo-image for optimized image loading
  • If source is not provided, the component automatically shows the first letter of username
  • The default borderRadius of 50 creates a perfect circle
  • Loading state shows an ActivityIndicator in the center
  • The component supports blurhash placeholders for smooth loading transitions
  • Image paths can use EXPO_PUBLIC_API_URL environment variable if set
  • The fallback initial is always white text on the specified background color
  • All styling uses black and white defaults - no theme dependencies required
Made by Krish Panchani X Thunder Develops • Built with ❤️ for the Expo React Native community
📦 View on npm