Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Avatar in React Native

Avatar

~9 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

An avatar shows a round profile picture – or, if none is available, a placeholder with the user's initials. Both cases can be covered by ONE reusable component.

1. Description

The circular crop comes from borderRadius set to exactly half the diameter (width/height: 48borderRadius: 24). For the initials fallback, the user's name is split into its words and the first letter of each is used.

2. Short example

<Image
  source={{ uri: imageUrl }}
  style={{ width: 48, height: 48, borderRadius: 24 }}
/>

3. Complete project: a contact list with avatars

npx create-expo-app avatar-demo
cd avatar-demo
components/Avatar.js
import { View, Image, Text, StyleSheet } from 'react-native';

const COLORS = ['#2563eb', '#16a34a', '#dc2626', '#9333ea', '#ea580c'];

function initialsOf(name) {
  return name
    .trim()
    .split(/\s+/)
    .slice(0, 2)
    .map((word) => word[0]?.toUpperCase())
    .join('');
}

function colorOf(name) {
  const sum = [...name].reduce((acc, char) => acc + char.charCodeAt(0), 0);
  return COLORS[sum % COLORS.length];
}

function Avatar({ name, imageUrl, size = 48 }) {
  const style = { width: size, height: size, borderRadius: size / 2 };

  if (imageUrl) {
    return <Image source={{ uri: imageUrl }} style={style} />;
  }

  return (
    <View style={[style, styles.placeholder, { backgroundColor: colorOf(name) }]}>
      <Text style={[styles.initials, { fontSize: size * 0.4 }]}>
        {initialsOf(name)}
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  placeholder: { alignItems: 'center', justifyContent: 'center' },
  initials: { color: 'white', fontWeight: 'bold' },
});

export default Avatar;
App.js
import { View, Text, FlatList, StyleSheet } from 'react-native';
import Avatar from './components/Avatar';

const CONTACTS = [
  { id: '1', name: 'Anna Berger', imageUrl: 'https://i.pravatar.cc/150?img=5' },
  { id: '2', name: 'Mehmet Yildiz', imageUrl: null },
  { id: '3', name: 'Sophie Klein', imageUrl: null },
];

export default function App() {
  return (
    <FlatList
      data={CONTACTS}
      keyExtractor={(item) => item.id}
      contentContainerStyle={styles.list}
      renderItem={({ item }) => (
        <View style={styles.row}>
          <Avatar name={item.name} imageUrl={item.imageUrl} />
          <Text style={styles.name}>{item.name}</Text>
        </View>
      )}
    />
  );
}

const styles = StyleSheet.create({
  list: { paddingTop: 60, paddingHorizontal: 16 },
  row: { flexDirection: 'row', alignItems: 'center', paddingVertical: 10 },
  name: { marginLeft: 12, fontSize: 16 },
});

4. Explanation

  • imageUrl ? <Image .../> : <View .../> – the component decides ITSELF whether to render a real image or the initials placeholder; the caller doesn't need to know.
  • colorOf(name) produces a deterministic (always the same) color per name – via the sum of character codes modulo the number of colors, instead of a random color on every render.
  • size / 2 instead of a fixed value makes the component reusable for different avatar sizes (e.g. small in a list, large on a profile screen) – ONE size prop drives width, height, AND rounding together.
  • [...name].reduce(...) instead of name.charCodeAt directly on the string, so it also works with names containing characters outside the basic Latin range (the spread operator splits correctly into individual characters).

5. Outputs

Ausgabe
Three contact rows: "Anna Berger" with a real round photo, "Mehmet Yildiz" with a colored circular placeholder and white initials "MY", "Sophie Klein" with a differently colored placeholder and initials "SK" – each followed by the full name next to it.