How to Use Avatar and AvatarGroup Components for User Display in Astryx
Astryx provides a flexible Avatar component that displays user images, initials, or fallback icons, and an AvatarGroup component that stacks multiple avatars with configurable overlap and overflow handling.
Astryx, Facebook's open-source design system, delivers robust components for user identity display. The Avatar and AvatarGroup components provide a complete solution for showing individual users and stacked groups while maintaining consistent sizing, spacing, and accessibility standards. These components leverage a shared context architecture and StyleX styling to coordinate layout across the UI.
Core Architecture of the Avatar Component
Implementation Details in Avatar.tsx
In packages/core/src/Avatar/Avatar.tsx, the Avatar component accepts src, fallbackSrc, name, size, and optional status props. The component resolves pixel dimensions through the resolveSize function, converting named sizes (like "medium" or "large") to numeric values via AvatarSizeContext.
The component implements a sophisticated fallback chain: it attempts to load the primary image, falls back to fallbackSrc if provided, then derives initials from the name prop, and finally displays a generic person icon if no text is available.
Accessibility Features and Status Indicators
Accessibility is handled through ARIA attributes: the component applies role="img" with aria-label when a name or alt prop is supplied, otherwise it renders as decorative with role="presentation". When using the status prop (typically with AvatarStatusDot from packages/core/src/Avatar/AvatarStatusDot.tsx), the component renders a status indicator positioned at the bottom-right corner using dynamic style calculations.
Building Stacked User Displays with AvatarGroup
Context-Driven Sizing and Overlap
The AvatarGroup component in packages/core/src/AvatarGroup/AvatarGroup.tsx manages stacked avatar layouts through AvatarGroupContext. This context shares size, overlap, and computed numeric values with all child avatars, ensuring consistent dimensions without prop drilling.
The overlap calculation uses numericSize * OVERLAP_RATIO (defaulting to 0.25), making avatars overlap proportionally based on their actual pixel dimensions. Children render as-is without introspection, allowing each avatar to maintain its own props such as individual status dots.
Handling Overflow with AvatarGroupOverflow
For lists exceeding display limits, AvatarGroupOverflow in packages/core/src/AvatarGroup/AvatarGroupOverflow.tsx consumes the group context via useAvatarGroup() to inherit sizing and spacing. It renders as a <button> when an onClick handler is provided, enabling interactive behaviors like opening a participant modal, or as a <span> for read-only displays. The component accepts custom children to override the default "+N" label.
Practical Implementation Examples
Basic Avatar with Initials Fallback
import {Avatar} from '@astryxdesign/core/Avatar';
export const Simple = () => (
<Avatar name="John Doe" size="medium" />
);
Avatar with Image and Status Dot
import {Avatar, AvatarStatusDot} from '@astryxdesign/core/Avatar';
export const WithImageAndStatus = () => (
<Avatar
src="https://i.pravatar.cc/150?img=1"
name="Jane Smith"
size="large"
status={<AvatarStatusDot variant="success" label="Online" />}
/>
);
Stacked Avatar Group with Overflow
import {Avatar, AvatarGroup, AvatarGroupOverflow} from '@astryxdesign/core/Avatar';
const users = [
{id: 1, src: 'https://i.pravatar.cc/150?img=2', name: 'Alice'},
{id: 2, src: 'https://i.pravatar.cc/150?img=3', name: 'Bob'},
{id: 3, src: 'https://i.pravatar.cc/150?img=4', name: 'Carol'},
{id: 4, src: 'https://i.pravatar.cc/150?img=5', name: 'David'},
];
export const Group = () => (
<AvatarGroup size="small">
{users.slice(0, 3).map(u => (
<Avatar key={u.id} src={u.src} name={u.name} />
))}
<AvatarGroupOverflow count={users.length - 3} />
</AvatarGroup>
);
Interactive Overflow Button
import {AvatarGroup, AvatarGroupOverflow, Avatar} from '@astryxdesign/core/Avatar';
export const ClickableGroup = () => {
const handleShowAll = () => alert('Show all participants');
return (
<AvatarGroup size="medium">
<Avatar src="https://i.pravatar.cc/150?img=6" name="User 1" />
<Avatar src="https://i.pravatar.cc/150?img=7" name="User 2" />
<AvatarGroupOverflow count={5} onClick={handleShowAll} />
</AvatarGroup>
);
};
Custom Overflow Content
import {AvatarGroup, AvatarGroupOverflow, Avatar} from '@astryxdesign/core/Avatar';
export const CustomOverflow = () => (
<AvatarGroup size="small">
<Avatar name="A" />
<Avatar name="B" />
<AvatarGroupOverflow count={12}>
<span style={{fontWeight: 600}}>+12</span>
</AvatarGroupOverflow>
</AvatarGroup>
);
Summary
- Avatar resolves sizing through
resolveSizeandAvatarSizeContext, supporting named sizes that convert to pixel values for consistent rendering. - Fallback chain progresses from primary image to fallback image, then initials, and finally a generic icon, ensuring users always see visual identification.
- AvatarGroup uses
AvatarGroupContextto share size and overlap values, calculating overlap asnumericSize * 0.25for proportional stacking. - AvatarGroupOverflow supports both interactive (button) and static (span) modes, with customizable content to replace the default count indicator.
- All components respect accessibility standards via ARIA roles and labels, and use StyleX for type-safe CSS-in-JS styling according to Astryx design tokens.
Frequently Asked Questions
How does the Avatar component handle image loading failures?
According to the source code in packages/core/src/Avatar/Avatar.tsx, the Avatar implements a cascading fallback system: if the primary src fails to load, it attempts the fallbackSrc prop. If that also fails or is undefined, it extracts initials from the name prop. If no name is provided, it renders a generic person icon as the final fallback.
Can I use Avatar outside of AvatarGroup without losing functionality?
Yes. While AvatarGroup provides AvatarGroupContext for coordinated sizing and overlap, the Avatar component functions independently using its own size prop and AvatarSizeContext. When used outside a group, it relies on the prop-based size resolution via resolveSize without requiring any group context providers.
How do I customize the overlap amount between avatars in a group?
The overlap ratio is hardcoded in packages/core/src/AvatarGroup/AvatarGroup.tsx as OVERLAP_RATIO = 0.25, meaning avatars overlap by 25% of their numeric size. To customize this, you would need to modify the source or wrap the component, as the current implementation calculates overlap as numericSize * OVERLAP_RATIO and passes this value through context to child avatars.
What accessibility features are built into the Avatar and AvatarGroup components?
The Avatar component applies role="img" with an aria-label derived from the name or alt props when available, making it accessible to screen readers. If no descriptive text is provided, it defaults to role="presentation" to indicate decorative content. The AvatarGroupOverflow component renders as a semantic <button> when interactive, ensuring keyboard navigability, or as a <span> for static displays.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →