Avatar Components
User avatars, profile pictures, and avatar groups built with TailwindCSS. Perfect for user profiles, comments, team sections, and social features. Copy, paste, and customize for React, Vue, or HTML.
1. Simple Avatar
Clean and simple avatar with different sizes and styles for user profiles.

Small (32px)

Medium (48px)

Large (64px)

XL (80px)
<!-- Small Avatar -->
<img src="https://randomuser.me/api/portraits/men/32.jpg" alt="User avatar" class="w-8 h-8 rounded-full border-2 border-gray-200 shadow-sm">
<!-- Medium Avatar -->
<img src="https://randomuser.me/api/portraits/women/44.jpg" alt="User avatar" class="w-12 h-12 rounded-full border-2 border-gray-200 shadow-sm">
<!-- Large Avatar -->
<img src="https://randomuser.me/api/portraits/men/67.jpg" alt="User avatar" class="w-16 h-16 rounded-full border-2 border-gray-200 shadow-sm">
<!-- Extra Large Avatar -->
<img src="https://randomuser.me/api/portraits/women/89.jpg" alt="User avatar" class="w-20 h-20 rounded-full border-2 border-gray-200 shadow-sm">
<template>
<img :src="user.avatar" :alt="user.name" :class="avatarClasses" />
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
user: {
type: Object,
required: true
},
size: {
type: String,
default: 'medium',
validator: (value) => ['small', 'medium', 'large', 'xl'].includes(value)
}
})
const avatarClasses = computed(() => {
const baseClasses = 'rounded-full border-2 border-gray-200 shadow-sm'
const sizeClasses = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16',
xl: 'w-20 h-20'
}
return `${baseClasses} ${sizeClasses[props.size]}`
})
</script>
import React from 'react'
const SimpleAvatar = ({ user, size = 'medium' }) => {
const getSizeClasses = (size) => {
const sizeMap = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16',
xl: 'w-20 h-20'
}
return sizeMap[size] || sizeMap.medium
}
return (
<img
src={user.avatar}
alt={user.name}
className={`rounded-full border-2 border-gray-200 shadow-sm ${getSizeClasses(size)}`}
/>
)
}
export default SimpleAvatar
2. Avatar with Initials
Fallback avatar using user initials with customizable background colors.
John Doe
Anna Smith
Mike Wilson
Sarah Johnson
<!-- Violet Avatar -->
<div class="w-16 h-16 bg-violet rounded-full flex items-center justify-center border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,0.8)]">
<span class="text-white text-lg font-bold">JD</span>
</div>
<!-- Green Avatar -->
<div class="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,0.8)]">
<span class="text-white text-lg font-bold">AS</span>
</div>
<!-- Orange Avatar -->
<div class="w-16 h-16 bg-orange-500 rounded-full flex items-center justify-center border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,0.8)]">
<span class="text-white text-lg font-bold">MW</span>
</div>
<!-- Red Avatar -->
<div class="w-16 h-16 bg-red-500 rounded-full flex items-center justify-center border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,0.8)]">
<span class="text-white text-lg font-bold">SJ</span>
</div>
<template>
<div :class="avatarClasses">
<span :class="textClasses">{{ initials }}</span>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
name: {
type: String,
required: true
},
size: {
type: String,
default: 'medium'
},
color: {
type: String,
default: 'violet'
}
})
const initials = computed(() => {
return props.name
.split(' ')
.map(word => word.charAt(0).toUpperCase())
.slice(0, 2)
.join('')
})
const avatarClasses = computed(() => {
const sizeClasses = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16',
xl: 'w-20 h-20'
}
const colorClasses = {
violet: 'bg-violet',
green: 'bg-green-500',
orange: 'bg-orange-500',
red: 'bg-red-500',
blue: 'bg-blue-500'
}
return `${sizeClasses[props.size]} ${colorClasses[props.color]} rounded-full flex items-center justify-center border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,0.8)]`
})
const textClasses = computed(() => {
const sizeClasses = {
small: 'text-xs',
medium: 'text-sm',
large: 'text-lg',
xl: 'text-xl'
}
return `text-white ${sizeClasses[props.size]} font-bold`
})
</script>
import React from 'react'
const InitialsAvatar = ({ name, size = 'medium', color = 'violet' }) => {
const getInitials = (name) => {
return name
.split(' ')
.map(word => word.charAt(0).toUpperCase())
.slice(0, 2)
.join('')
}
const getSizeClasses = (size) => {
const sizeMap = {
small: { container: 'w-8 h-8', text: 'text-xs' },
medium: { container: 'w-12 h-12', text: 'text-sm' },
large: { container: 'w-16 h-16', text: 'text-lg' },
xl: { container: 'w-20 h-20', text: 'text-xl' }
}
return sizeMap[size] || sizeMap.medium
}
const getColorClass = (color) => {
const colorMap = {
violet: 'bg-violet',
green: 'bg-green-500',
orange: 'bg-orange-500',
red: 'bg-red-500',
blue: 'bg-blue-500'
}
return colorMap[color] || colorMap.violet
}
const sizeClasses = getSizeClasses(size)
const colorClass = getColorClass(color)
return (
<div className={`${sizeClasses.container} ${colorClass} rounded-full flex items-center justify-center border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,0.8)]`}>
<span className={`text-white ${sizeClasses.text} font-bold`}>
{getInitials(name)}
</span>
</div>
)
}
export default InitialsAvatar
3. Avatar Group
Stack multiple avatars to show team members or users with overflow counter.
Small Group (Team of 5)





Medium Group with Counter




Large Group



<!-- Small Avatar Group -->
<div class="flex -space-x-2">
<img class="w-8 h-8 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/1.jpg" alt="User 1">
<img class="w-8 h-8 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/men/2.jpg" alt="User 2">
<img class="w-8 h-8 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/3.jpg" alt="User 3">
<img class="w-8 h-8 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/men/4.jpg" alt="User 4">
<img class="w-8 h-8 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/5.jpg" alt="User 5">
</div>
<!-- Medium Avatar Group with Counter -->
<div class="flex -space-x-3">
<img class="w-12 h-12 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/men/10.jpg" alt="User 1">
<img class="w-12 h-12 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/11.jpg" alt="User 2">
<img class="w-12 h-12 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/men/12.jpg" alt="User 3">
<img class="w-12 h-12 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/13.jpg" alt="User 4">
<span class="w-12 h-12 rounded-full bg-violet border-2 border-white shadow flex items-center justify-center text-white font-bold text-sm">+5</span>
</div>
<!-- Large Avatar Group -->
<div class="flex -space-x-4">
<img class="w-16 h-16 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/20.jpg" alt="User 1">
<img class="w-16 h-16 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/men/21.jpg" alt="User 2">
<img class="w-16 h-16 rounded-full border-2 border-white shadow" src="https://randomuser.me/api/portraits/women/22.jpg" alt="User 3">
<span class="w-16 h-16 rounded-full bg-gradient-to-r from-violet to-purple-600 border-2 border-white shadow flex items-center justify-center text-white font-bold text-lg">+12</span>
</div>
<template>
<div :class="containerClasses">
<img
v-for="(user, index) in displayUsers"
:key="user.id"
:src="user.avatar"
:alt="user.name"
:class="avatarClasses"
/>
<span v-if="remainingCount > 0" :class="counterClasses">
+{{ remainingCount }}
</span>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
users: {
type: Array,
required: true
},
maxDisplay: {
type: Number,
default: 4
},
size: {
type: String,
default: 'medium'
}
})
const displayUsers = computed(() => {
return props.users.slice(0, props.maxDisplay)
})
const remainingCount = computed(() => {
return Math.max(0, props.users.length - props.maxDisplay)
})
const containerClasses = computed(() => {
const spacingMap = {
small: 'flex -space-x-2',
medium: 'flex -space-x-3',
large: 'flex -space-x-4'
}
return spacingMap[props.size] || spacingMap.medium
})
const avatarClasses = computed(() => {
const sizeMap = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16'
}
const sizeClass = sizeMap[props.size] || sizeMap.medium
return `${sizeClass} rounded-full border-2 border-white shadow`
})
const counterClasses = computed(() => {
const sizeMap = {
small: { container: 'w-8 h-8', text: 'text-xs' },
medium: { container: 'w-12 h-12', text: 'text-sm' },
large: { container: 'w-16 h-16', text: 'text-lg' }
}
const size = sizeMap[props.size] || sizeMap.medium
return `${size.container} rounded-full bg-violet border-2 border-white shadow flex items-center justify-center text-white font-bold ${size.text}`
})
</script>
import React from 'react'
const AvatarGroup = ({ users, maxDisplay = 4, size = 'medium' }) => {
const displayUsers = users.slice(0, maxDisplay)
const remainingCount = Math.max(0, users.length - maxDisplay)
const getClasses = (size) => {
const sizeMap = {
small: {
container: 'flex -space-x-2',
avatar: 'w-8 h-8',
counter: { container: 'w-8 h-8', text: 'text-xs' }
},
medium: {
container: 'flex -space-x-3',
avatar: 'w-12 h-12',
counter: { container: 'w-12 h-12', text: 'text-sm' }
},
large: {
container: 'flex -space-x-4',
avatar: 'w-16 h-16',
counter: { container: 'w-16 h-16', text: 'text-lg' }
}
}
return sizeMap[size] || sizeMap.medium
}
const classes = getClasses(size)
return (
<div className={classes.container}>
{displayUsers.map((user) => (
<img
key={user.id}
src={user.avatar}
alt={user.name}
className={`${classes.avatar} rounded-full border-2 border-white shadow`}
/>
))}
{remainingCount > 0 && (
<span className={`${classes.counter.container} rounded-full bg-violet border-2 border-white shadow flex items-center justify-center text-white font-bold ${classes.counter.text}`}>
+{remainingCount}
</span>
)}
</div>
)
}
export default AvatarGroup
4. Avatar with Status
Avatar with online/offline status indicator for user presence.

Online

Away

Busy

Offline
<!-- Online Status -->
<div class="relative">
<img src="https://randomuser.me/api/portraits/men/30.jpg" alt="User avatar" class="w-16 h-16 rounded-full border-2 border-gray-200 shadow">
<span class="absolute bottom-0 right-0 w-5 h-5 bg-green-500 border-2 border-white rounded-full"></span>
</div>
<!-- Away Status -->
<div class="relative">
<img src="https://randomuser.me/api/portraits/women/31.jpg" alt="User avatar" class="w-16 h-16 rounded-full border-2 border-gray-200 shadow">
<span class="absolute bottom-0 right-0 w-5 h-5 bg-yellow-500 border-2 border-white rounded-full"></span>
</div>
<!-- Busy Status -->
<div class="relative">
<img src="https://randomuser.me/api/portraits/men/32.jpg" alt="User avatar" class="w-16 h-16 rounded-full border-2 border-gray-200 shadow">
<span class="absolute bottom-0 right-0 w-5 h-5 bg-red-500 border-2 border-white rounded-full"></span>
</div>
<!-- Offline Status -->
<div class="relative">
<img src="https://randomuser.me/api/portraits/women/33.jpg" alt="User avatar" class="w-16 h-16 rounded-full border-2 border-gray-200 shadow grayscale opacity-75">
<span class="absolute bottom-0 right-0 w-5 h-5 bg-gray-400 border-2 border-white rounded-full"></span>
</div>
<template>
<div class="relative">
<img :src="user.avatar" :alt="user.name" :class="avatarClasses" />
<span :class="statusClasses"></span>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
user: {
type: Object,
required: true
},
status: {
type: String,
default: 'online',
validator: (value) => ['online', 'away', 'busy', 'offline'].includes(value)
},
size: {
type: String,
default: 'medium'
}
})
const avatarClasses = computed(() => {
const sizeMap = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16',
xl: 'w-20 h-20'
}
const baseClasses = 'rounded-full border-2 border-gray-200 shadow'
const sizeClass = sizeMap[props.size] || sizeMap.medium
const statusClass = props.status === 'offline' ? 'grayscale opacity-75' : ''
return `${baseClasses} ${sizeClass} ${statusClass}`
})
const statusClasses = computed(() => {
const statusColors = {
online: 'bg-green-500',
away: 'bg-yellow-500',
busy: 'bg-red-500',
offline: 'bg-gray-400'
}
const sizeMap = {
small: 'w-3 h-3',
medium: 'w-4 h-4',
large: 'w-5 h-5',
xl: 'w-6 h-6'
}
const colorClass = statusColors[props.status] || statusColors.online
const sizeClass = sizeMap[props.size] || sizeMap.medium
return `absolute bottom-0 right-0 ${sizeClass} ${colorClass} border-2 border-white rounded-full`
})
</script>
import React from 'react'
const AvatarWithStatus = ({ user, status = 'online', size = 'medium' }) => {
const getAvatarClasses = (status, size) => {
const sizeMap = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16',
xl: 'w-20 h-20'
}
const baseClasses = 'rounded-full border-2 border-gray-200 shadow'
const sizeClass = sizeMap[size] || sizeMap.medium
const statusClass = status === 'offline' ? 'grayscale opacity-75' : ''
return `${baseClasses} ${sizeClass} ${statusClass}`
}
const getStatusClasses = (status, size) => {
const statusColors = {
online: 'bg-green-500',
away: 'bg-yellow-500',
busy: 'bg-red-500',
offline: 'bg-gray-400'
}
const sizeMap = {
small: 'w-3 h-3',
medium: 'w-4 h-4',
large: 'w-5 h-5',
xl: 'w-6 h-6'
}
const colorClass = statusColors[status] || statusColors.online
const sizeClass = sizeMap[size] || sizeMap.medium
return `absolute bottom-0 right-0 ${sizeClass} ${colorClass} border-2 border-white rounded-full`
}
return (
<div className="relative">
<img
src={user.avatar}
alt={user.name}
className={getAvatarClasses(status, size)}
/>
<span className={getStatusClasses(status, size)}></span>
</div>
)
}
export default AvatarWithStatus
5. Avatar Card with Name & Role
A user profile card with avatar, name, and role—great for team sections and testimonials.

Samuel Green
Product Designer
<div class="bg-white border-2 border-black rounded-xl shadow-[4px_4px_0px_0px_rgba(0,0,0,0.8)] p-6 flex flex-col items-center">
<img src="https://randomuser.me/api/portraits/men/85.jpg" alt="User avatar" class="w-20 h-20 rounded-full border-2 border-violet shadow mb-4">
<h3 class="font-bold text-lg mb-1">Samuel Green</h3>
<p class="text-sm text-gray-500 mb-2">Product Designer</p>
<div class="flex gap-2 mt-2">
<span class="inline-block w-3 h-3 bg-green-500 rounded-full"></span>
<span class="text-xs text-gray-400">Active</span>
</div>
</div>
<template>
<div class="bg-white border-2 border-black rounded-xl shadow-[4px_4px_0px_0px_rgba(0,0,0,0.8)] p-6 flex flex-col items-center">
<img :src="user.avatar" :alt="user.name" class="w-20 h-20 rounded-full border-2 border-violet shadow mb-4">
<h3 class="font-bold text-lg mb-1">{{ user.name }}</h3>
<p class="text-sm text-gray-500 mb-2">{{ user.role }}</p>
<div class="flex gap-2 mt-2">
<span class="inline-block w-3 h-3 bg-green-500 rounded-full"></span>
<span class="text-xs text-gray-400">Active</span>
</div>
</div>
</template>
<script setup>
const props = defineProps({
user: {
type: Object,
required: true
}
})
</script>
import React from 'react'
const AvatarCard = ({ user }) => (
<div className="bg-white border-2 border-black rounded-xl shadow-[4px_4px_0px_0px_rgba(0,0,0,0.8)] p-6 flex flex-col items-center">
<img src={user.avatar} alt={user.name} className="w-20 h-20 rounded-full border-2 border-violet shadow mb-4" />
<h3 className="font-bold text-lg mb-1">{user.name}</h3>
<p className="text-sm text-gray-500 mb-2">{user.role}</p>
<div className="flex gap-2 mt-2">
<span className="inline-block w-3 h-3 bg-green-500 rounded-full"></span>
<span className="text-xs text-gray-400">Active</span>
</div>
</div>
)
export default AvatarCard