Skip to Content
Hashti Design System
Components

Avatar

Visual representation of a user, team, or entity with image, initials fallback, and status indicator.

Avatar

Avatars visually represent users, teams, organizations, or automated agents. Hashti’s Avatar and AvatarGroup components feature automatic image error fallbacks, grapheme-safe international initials (with native support for Persian and Arabic scripts), five standardized geometric sizes, presence badges, and stacked group layouts.

AvatarScalable identity tokens with automated initials fallback.

Architectural Affordances & Grapheme Clusters

In international design systems, extracting the first letter of a name often fails with non-Latin scripts (e.g., Persian گ, چ, Arabic ligatures, or multi-byte emoji combinations). Hashti’s Avatar incorporates an Intl.Segmenter engine via getInitials:

"Sara Moradi"       ──► "SM"
"سارا مرادی"         ──► "سم"  (Persian grapheme cluster safe)
"Failed Image URL"  ──► Fallback to Initials or Icon
  • Graceful Fallback Sequence: Image ──(error)──► Initials ──(missing name)──► Custom Fallback ──(empty)──► Default User Icon.
  • Presence Indicators: High-visibility status dots (online, offline, away, busy, dnd) with accessible screen reader status labels.
  • AvatarGroup Composition: Stacks multiple members with negative overlapping margins, automatic +N count calculation, and inherited size tokens.

Import

import { Avatar, AvatarGroup, getInitials } from "@hashti/react";
import type { AvatarProps, AvatarGroupProps, AvatarSize, AvatarPresence } from "@hashti/react";

Usage Examples

Basic Image Avatar

When a valid image URL is provided in src:

import { Avatar } from "@hashti/react";

export function BasicAvatarDemo() {
  return (
    <div className="flex gap-4 items-center">
      <Avatar
        src="https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=128&q=80"
        name="Elena Rostova"
        alt="Portrait of Elena Rostova"
      />
      <div>
        <div className="font-medium text-sm">Elena Rostova</div>
        <div className="text-xs text-neutral-500">Principal Systems Architect</div>
      </div>
    </div>
  );
}

Grapheme-Safe Initials Fallback

When src is missing or fails to load, Avatar automatically derives initials from name. It safely handles both Latin and Persian/Arabic names:

import { Avatar } from "@hashti/react";

export function InitialsAvatarDemo() {
  return (
    <div className="flex flex-wrap gap-4 items-center">
      {/* English initials -> "AS" */}
      <Avatar name="Ali Soleimani" />

      {/* Persian initials -> "سم" (Sara Moradi) */}
      <Avatar name="سارا مرادی" lang="fa" />

      {/* Persian single name -> "ر" (Ramin) */}
      <Avatar name="رامین" lang="fa" />

      {/* French / German compound names */}
      <Avatar name="Jean-Luc Picard" />
    </div>
  );
}

Sizes

Hashti offers five standardized sizes from xs (24px) up to xl (64px):

import { Avatar } from "@hashti/react";

export function AvatarSizesDemo() {
  return (
    <div className="flex items-end gap-3">
      <Avatar size="xs" name="Kian" />
      <Avatar size="sm" name="Kian" />
      <Avatar size="md" name="Kian" />
      <Avatar size="lg" name="Kian" />
      <Avatar size="xl" name="Kian" />
    </div>
  );
}
SizeDimensionUse Cases
xs24pxDense table cells, inline comments, chat thread sub-replies
sm32pxHeader user menus, list items, card author stamps
md40px (Default)Standard profile cards, member directories
lg48pxModal profile overviews, workspace headers
xl64pxAccount settings pages, profile hero sections

Presence Status Badges

Add a live activity indicator using the presence prop:

import { Avatar } from "@hashti/react";

export function AvatarPresenceDemo() {
  return (
    <div className="flex gap-4 items-center">
      <Avatar name="Kav" presence="online" presenceLabel="Online and active" />
      <Avatar name="Zahra" presence="away" presenceLabel="Away from keyboard" />
      <Avatar name="David" presence="busy" presenceLabel="In a design review" />
      <Avatar name="Nima" presence="dnd" presenceLabel="Do not disturb" />
      <Avatar name="Reza" presence="offline" presenceLabel="Offline" />
    </div>
  );
}

AvatarGroup (Stacked Cluster)

Group multiple team members with AvatarGroup. Use the max prop to constrain the display and show an overflow counter:

import { AvatarGroup, Avatar } from "@hashti/react";

export function AvatarGroupDemo() {
  return (
    <div className="flex flex-col gap-4">
      {/* Default group */}
      <AvatarGroup size="md" max={3}>
        <Avatar name="Soran" />
        <Avatar name="Maryam" />
        <Avatar name="Farhad" />
        <Avatar name="Kaveh" />
        <Avatar name="Niloufar" />
      </AvatarGroup>

      {/* Small group */}
      <AvatarGroup size="sm" max={4}>
        <Avatar name="A" />
        <Avatar name="B" />
        <Avatar name="C" />
        <Avatar name="D" />
        <Avatar name="E" />
        <Avatar name="F" />
      </AvatarGroup>
    </div>
  );
}

Props Reference

Avatar Props

PropTypeDefaultDescription
srcstring—Image source URL.
altstring''Alt text for the image element.
namestring—Full name used to generate initials and accessible label.
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Geometric size (inherited from AvatarGroup if present).
presence'online' | 'offline' | 'away' | 'busy' | 'dnd'—Current presence status indicator.
presenceLabelstring—Accessible screen reader description for the presence status.
fallbackReactNode—Custom fallback node rendered if image fails and name is not supplied.
classNamestring—Additional CSS class names.

AvatarGroup Props

PropTypeDefaultDescription
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Inherited size for all member avatars in the group.
maxnumber—Maximum number of avatars visible before rendering the +N badge.
overflowRenderer(count: number) => ReactNode—Custom renderer for the overflow count badge.
childrenReactNode—Collection of <Avatar /> components.
classNamestring—Additional CSS class names.

Accessibility & Internationalization

  • Semantic Role: Renders with role="img" and calculates an accessible aria-label falling back in order: aria-label ➔ name ➔ alt ➔ "Avatar".
  • Initials Hidden from Assistive Voice: Initials are wrapped in <span aria-hidden="true"> to prevent screen readers from attempting to pronounce initials as strange phonetic syllables.
  • Presence Status Announcement: Presence dots render with role="status" and aria-label={presenceLabel ?? presence}.
  • International Grapheme Segmentation: Uses Intl.Segmenter to avoid splitting compound characters or emoji ligatures, ensuring polite rendering across all languages.
  • AvatarGroup Semantics: The group wrapper receives role="group" with an accessible label on the overflow counter (e.g., aria-label="3 more members").

WAI-ARIA & Data Attributes

AttributeTargetDescription
[data-size]AvatarAvatar diameter scale (xs, sm, md, lg, xl).