Avatar
Display user avatars with support for images, initials, icons, status indicators, and various styling options. Built for Pulse Framework with full reactivity support.
Import
import { Avatar, Pulse } from '@odyssee/components';Basic Usage
With Initials
Display user initials when no image is available.
Sizes
Five size options are available: xs, sm, md, lg, and xl.
Rounded Styles
Control the border radius with the rounded prop.
Colors for Initials
When using initials, you can customize the color scheme with color and colorVariant props.
Status Indicator
Add status indicators to show online/offline state.
Status Position
Control the position of the status indicator.
Icon Placeholder
Display a default icon when no image or initials are provided.
With Tooltip
Add tooltips to provide additional information.
const avatarWithTooltip = (
<Avatar
src="https://images.unsplash.com/photo-1568602471122-7832951cc4c5"
status="online"
tooltip="Mark Wanner is online"
/>
);Clickable Avatar
Make avatars clickable for navigation or actions.
const clickableAvatar = (
<Avatar
src="https://images.unsplash.com/photo-1568602471122-7832951cc4c5"
href="/profile/user-123"
/>
);
// Or with onClick
const onClickAvatar = (
<Avatar
src="https://images.unsplash.com/photo-1568602471122-7832951cc4c5"
onClick={() => console.log('Avatar clicked!')}
/>
);Reactive Status
Control status dynamically with Pulse signals.
const userStatus = Pulse.signal<'online' | 'offline' | 'away' | 'busy'>('online');
// Simulate status changes
setInterval(() => {
const statuses = ['online', 'offline', 'away', 'busy'] as const;
const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
userStatus(randomStatus);
}, 3000);
const reactiveAvatar = (
<Avatar
src="https://images.unsplash.com/photo-1568602471122-7832951cc4c5"
status={userStatus}
/>
);Complete Example
Here's a comprehensive example with multiple features:
import { Avatar, Badge, Pulse } from '@odyssee/components';
const UserProfile = () => {
const user = Pulse.signal({
name: 'Mark Wanner',
avatar: 'https://images.unsplash.com/photo-1568602471122-7832951cc4c5',
status: 'online' as const,
role: 'Admin',
initials: 'MW'
});
const handleAvatarClick = () => {
console.log('Navigate to profile:', user().name);
};
return (
<div class="flex items-center gap-4 p-6 bg-white rounded-lg shadow">
{/* Avatar with status */}
<Avatar
src={user().avatar}
alt={user().name}
status={user().status}
statusPosition="bottom"
size="lg"
onClick={handleAvatarClick}
tooltip={`${user().name} is ${user().status}`}
/>
{/* User info */}
<div class="flex-1">
<div class="flex items-center gap-2">
<h3 class="text-lg font-semibold">{user().name}</h3>
<Badge
variant="soft"
color="primary"
size="sm"
>
{user().role}
</Badge>
</div>
<p class="text-sm text-gray-500">
Status: <span class="capitalize">{user().status}</span>
</p>
</div>
</div>
);
};Props
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | - | Image URL |
alt | string | "Avatar" | Image alt text |
name | string | - | User name (used to generate initials) |
initials | string | - | Display initials instead of image |
variant | "image" | "initials" | "icon" | Auto-detected | Avatar display variant |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Avatar size |
rounded | true | false | "full" | "lg" | "full" | Border radius style |
color | "gray" | "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "white" | "gray" | Color for initials variant |
colorVariant | "solid" | "soft" | "outline" | "solid" | Color style for initials |
status | "none" | "online" | "offline" | "away" | "busy" | "none" | Status indicator |
statusPosition | "top" | "bottom" | "bottom" | Status indicator position |
statusColor | string | - | Custom status indicator color |
tooltip | string | - | Tooltip text on hover |
href | string | - | Make avatar a link |
onClick | (event: Event) => void | - | Click event handler |
className | string | - | Additional CSS classes |
id | string | Auto-generated | HTML id attribute |
Accessibility
The Avatar component follows accessibility best practices:
- ✅ Proper
altattributes for images - ✅ Semantic HTML structure
- ✅ Keyboard navigation support for clickable avatars
- ✅ ARIA labels for status indicators
- ✅ Tooltips for additional context
- ✅ Sufficient color contrast
ARIA Attributes
const accessibleAvatar = (
<Avatar
src="..."
alt="John Doe profile picture"
status="online"
aria-label="John Doe, currently online"
/>
);Best Practices
✅ Do
- Always provide meaningful
alttext for images - Use appropriate sizes for the context
- Show status indicators for real-time communication apps
- Use initials as fallback when images fail to load
- Provide tooltips for additional context
// Good: Proper alt text and fallback
const goodAvatar = (
<Avatar
src="https://..."
alt="John Doe"
initials="JD"
name="John Doe"
/>
);❌ Don't
- Don't use very large images (optimize for size)
- Don't forget alt text
- Don't use avatars for decorative purposes without proper ARIA
- Don't make avatars too small to recognize
// Bad: No alt text, no fallback
const badAvatar = (
<Avatar src="https://..." />
);
// Better: With proper attributes
const betterAvatar = (
<Avatar
src="https://..."
alt="User profile picture"
initials="JD"
/>
);Use Cases
User Lists
const users = [
{ name: 'Alice Cooper', avatar: '...', status: 'online' },
{ name: 'Bob Smith', avatar: '...', status: 'away' },
{ name: 'Charlie Brown', initials: 'CB', status: 'offline' }
];
const userList = (
<div class="space-y-3">
{users.map(user => (
<div class="flex items-center gap-3">
<Avatar
src={user.avatar}
initials={user.initials}
name={user.name}
status={user.status}
size="sm"
/>
<span>{user.name}</span>
</div>
))}
</div>
);Comment Section
const Comment = ({ author, text, timestamp }) => (
<div class="flex gap-3">
<Avatar
src={author.avatar}
alt={author.name}
size="md"
/>
<div class="flex-1">
<div class="flex items-center gap-2">
<span class="font-semibold">{author.name}</span>
<span class="text-xs text-gray-500">{timestamp}</span>
</div>
<p class="mt-1 text-gray-700">{text}</p>
</div>
</div>
);Team Members
const teamMembers = (
<div class="flex -space-x-2">
<Avatar
src="..."
size="md"
tooltip="Alice Cooper"
/>
<Avatar
src="..."
size="md"
tooltip="Bob Smith"
/>
<Avatar
src="..."
size="md"
tooltip="Charlie Brown"
/>
<Avatar
initials="+5"
color="gray"
size="md"
tooltip="5 more members"
/>
</div>
);Styling & Theming
All avatar styles use Tailwind CSS classes and support dark mode automatically.
Custom Styling
const customAvatar = (
<Avatar
src="..."
className="ring-4 ring-blue-500 ring-offset-2"
/>
);TypeScript
Full TypeScript support with complete type definitions:
import type { AvatarProps } from '@odyssee/components';
const props: AvatarProps = {
src: 'https://...',
alt: 'User Avatar',
size: 'md',
status: 'online',
onClick: (e: Event) => {
console.log('Clicked!');
}
};
const avatar = <Avatar {...props} />;Related Components
- AvatarGroup - Display multiple avatars together
- Badge - For status indicators
- Tooltip - For additional information
Version: 1.0.0
Last Updated: January 2025