DHxWhy

Avatar Status Ring – Presence Ring that Animates Speaking Level, Upload Progress and Status Changes

Component

About

Avatar Status Ring for React and Tailwind CSS (shadcn/ui): presence drawn as a ring instead of a dot — solid online, dashed away, red busy, thicker with the voice level while speaking, filling clockwise while uploading. It is built to show what a person is doing right now, animating every change in colour, dash pattern and thickness. Controlled status, level and progress props, tone overrides, silhouette fallback, aria-label, reduced motion, light and dark, and a stacked group. Use it for call grids, chat headers, team lists and voice agents. The included demo scripts a speaker and an upload and makes no network requests. Requires React and lucide-react only, with no animation library.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Avatar Status Ring – Presence Ring that Animates Speaking Level, Upload Progress and Status Changes to your project and fits it to your theme.

Code

How Avatar Status Ring – Presence Ring that Animates Speaking Level, Upload Progress and Status Changes is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import { AVATAR_STATUS_LABEL, AvatarStatusRing, AvatarStatusRingGroup } from "@/components/ui/avatar-status-ring";
import type { AvatarStatus, AvatarStatusRingGroupItem } from "@/components/ui/avatar-status-ring";

type DemoProps = { autoplay?: boolean };

const HEADSHOTS = {
  "photo-1507003211169-0a1dd7228f2d": "data:image/webp;base64,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",
  "photo-1573497019940-1c28c88b4f3e": "data:image/webp;base64,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",
  "photo-1500648767791-00dcc994a43e": "data:image/webp;base64,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",
  "photo-1494790108377-be9c29b29330": "data:image/webp;base64,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",
  "photo-1560250097-0b93528c311a": "data:image/webp;base64,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",
  "photo-1573496358961-3c82861ab8f4": "data:image/webp;base64,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",
  "photo-1595211877493-41a4e5f236b3": "data:image/webp;base64,UklGRrYDAABXRUJQVlA4IKoDAADQFgCdASqAAIAAPpFCnUmlo6MhLBSpMLASCWcA1UeFMj53lZwCtwaH5qXitJgIBz5+B+TZYewFCi1C1Z8mUY27lPVCz7O+gmIhsq2wtSf8RPb2WknZeI/jVok+phdzPflo6VrmGPr/kjvC2yltkf+s2PXrpE6mvb2Rhois2/0gXUv0huH/yw3CqcIWJGNpPa09iirIPs7efzrKHIDbPTVx1KbbstR0M8bbg8lssrqqPePrz44zP3m1GQmcXTN1wAD++bHqketMPt/+3CIIb3gCbd2N+z9ongGE5a1+KOPYTsz86YZj9dgbs2NvIdlE8ZMYb7TYkYzRP9v7PL1bI3WzsIJ9J2LU5Jx4U8GRjlBWH+aflE4yxYMzzxBYrPR7m//EMcYL3q7Jm/bR0wv48hDGqbn4xJ+j8DedQCuBrxG45cF0uNydgN21W20Y6M53YdIQtr/5SBgEownxVvr7r17zA45SvC/3R+bRg51R8QmlE46RLYGMgffiqoa+mED6ZFwo+do1f46IiuFwp/vi+sBlwWbgQ2iqvc9koUxW3qqERZZ3tk/n+djWscuZSoaoQJxVoNLINlNAy1C1dE+W09IKoEVP9lDbFkQcR5P1AIqQ4xcXK4qcUd450dpcuAITIn4IvVY5Af8m/GJglhMYm33n4TuTDKcngYpDTVFIfQPrLx0DKT/N5NKjQGC/EFtfVbBnQilKk6Fdb7v0/yomrLKLMQxHByvcX50P7vWiMQcP8SYAxwcl89OUlj7vOs4gY+qFjCZeBt3Db2QNmv14VZAx17k2+yxg7j/g/Vnm9az+pCisOYYwhT2y/2OSPY80ZrRC+OBDZkNcwlYq6OfUrusEs/UI+WDCIu8aPTGlUyRRA4QyLdXSmZZJG08qmBPaKgTUUdlr9TpnioDurv1e/hm3/nEc1yIvnJseWAeHX0ZGEB3HWnQfu9ph7yeu9+r08QcRh8q8FSoVcTfNYMezyZYPdxDivs0enr1rvinNIdkpjikCS+Qb70sjPkHuhSMkIOwDohBKmeGb9uMCRdGKlAlMfk+WSzeqi4AgY0Saiidm0PR0sBqjgCCsBBQ34DK4oP0+AMJzb5aTyHwQe1OoLuCNioXOIMvWT1SshWDNzMGdQZsAIBy7HWfp7FWc/WB3jEUdL0tjnhG5z184V1dIpfegTrIBX+rBy5El9in/etMtxry1UsKbzJkcBL97UJ3Kg+Yk4i0yP00aPNfJdERul4C0XluG+V8J8snAAA==",
  "photo-1699899657680-421c2c2d5064": "data:image/webp;base64,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",
  "photo-1705645930353-0e335311ef20": "data:image/webp;base64,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",
} as const;

const photo = (id: keyof typeof HEADSHOTS) => HEADSHOTS[id];

const CALL = {
  jordan: { name: "Jordan Lee", photo: photo("photo-1507003211169-0a1dd7228f2d") },
  mina: { name: "Mina Park", photo: photo("photo-1573497019940-1c28c88b4f3e") },
  theo: { name: "Theo Alvarez", photo: photo("photo-1500648767791-00dcc994a43e") },
  sora: { name: "Sora Kim", photo: photo("photo-1494790108377-be9c29b29330") },
} as const;

type CallId = keyof typeof CALL;

const ORDER: CallId[] = ["jordan", "mina", "theo", "sora"];

type Presence = { status: AvatarStatus; level?: number; progress?: number };
type Presences = { [id in CallId]: Presence };

const INITIAL: Presences = {
  jordan: { status: "online" },
  mina: { status: "online" },
  theo: { status: "away" },
  sora: { status: "online" },
};

const LAB: Presences = {
  jordan: { status: "online" },
  mina: { status: "speaking", level: 0.2 },
  theo: { status: "away" },
  sora: { status: "uploading", progress: 0.25 },
};

const CHANNEL: AvatarStatusRingGroupItem[] = [
  { id: "lucas", name: "Lucas Moreau", alt: "Lucas Moreau", src: photo("photo-1560250097-0b93528c311a"), status: "online" },
  { id: "amara", name: "Amara Okafor", alt: "Amara Okafor", src: photo("photo-1573496358961-3c82861ab8f4"), status: "online" },
  { id: "noah", name: "Noah Fischer", alt: "Noah Fischer", src: photo("photo-1595211877493-41a4e5f236b3"), status: "away" },
  { id: "hanna", name: "Hanna Berg", alt: "Hanna Berg", src: photo("photo-1699899657680-421c2c2d5064"), status: "busy" },
  { id: "felix", name: "Felix Brandt", alt: "Felix Brandt", src: photo("photo-1705645930353-0e335311ef20"), status: "offline" },
  { id: "priya", name: "Priya Nair", alt: "Priya Nair", status: "online" },
  { id: "omar", name: "Omar Haddad", alt: "Omar Haddad", status: "offline" },
  { id: "elin", name: "Elin Sandberg", alt: "Elin Sandberg", status: "away" },
];

const WAVE = [0.35, 0.6, 0.85, 0.7, 0.4, 0.25, 0.3, 0.55, 0.9, 0.75, 0.5, 0.3, 0.2, 0.45, 0.8, 0.65, 0.4, 0.6, 0.85, 0.5, 0.3, 0.2, 0.4, 0.7, 0.9, 0.6, 0.35, 0.25, 0.5, 0.75, 0.55, 0.3];
const WAVE_MS = 60;
const UPLOAD_AT = 2200;
const UPLOAD_MS = 2400;
const UPLOAD_TICK_MS = 80;
const LOOP_MS = 9000;
const BROKEN_SRC = "data:image/webp;base64,AAAA";

const clamp01 = (value: number) => Math.min(1, Math.max(0, value));

const phraseOf = (presence: Presence) =>
  presence.status === "uploading" ? `${AVATAR_STATUS_LABEL.uploading} · ${Math.round(clamp01(presence.progress ?? 0) * 100)}%` : AVATAR_STATUS_LABEL[presence.status];

const isCallId = (value: unknown): value is CallId => typeof value === "string" && value in CALL;
const isStatus = (value: unknown): value is AvatarStatus => typeof value === "string" && value in AVATAR_STATUS_LABEL;

export default function Demo({ autoplay = true }: DemoProps) {
  const params = React.useMemo(() => new URLSearchParams(typeof window === "undefined" ? "" : window.location.search), []);
  const lab = params.get("lab") === "1";
  const broken = params.get("broken") === "1";
  const toned = params.get("tone") === "1";
  const thick = params.get("thick") === "1";
  const announceAll = params.get("announce") === "1";
  const [presences, setPresences] = React.useState(lab ? LAB : INITIAL);
  const [reduced, setReduced] = React.useState(true);
  const [paused, setPaused] = React.useState(false);
  const [run, setRun] = React.useState(0);
  const rootRef = React.useRef(null as HTMLElement | null);

  React.useEffect(() => {
    const media = window.matchMedia("(prefers-reduced-motion: reduce)");
    const update = () => setReduced(media.matches);
    update();
    media.addEventListener("change", update);
    return () => media.removeEventListener("change", update);
  }, []);

  const patch = React.useCallback((id: CallId, next: Presence) => {
    setPresences((previous) => ({ ...previous, [id]: next }));
  }, []);

  React.useEffect(() => {
    if (!lab) return;
    const onLab = (event: Event) => {
      const detail: unknown = event instanceof CustomEvent ? event.detail : null;
      if (!detail || typeof detail !== "object") return;
      const { who, status, level, progress } = detail as { who?: unknown; status?: unknown; level?: unknown; progress?: unknown };
      if (!isCallId(who)) return;
      setPresences((previous) => {
        const current = previous[who];
        return {
          ...previous,
          [who]: {
            status: isStatus(status) ? status : current.status,
            level: typeof level === "number" ? level : current.level,
            progress: typeof progress === "number" ? progress : current.progress,
          },
        };
      });
    };
    window.addEventListener("asr-lab", onLab);
    return () => window.removeEventListener("asr-lab", onLab);
  }, [lab]);

  React.useEffect(() => {
    if (!autoplay || lab || paused) return;
    const root = rootRef.current;
    const started = performance.now();
    let steps = 0;
    const timers: number[] = [];
    const intervals: number[] = [];
    if (root) {
      root.dataset.tourStarted = started.toFixed(1);
      root.dataset.tourStep = "0";
    }
    const at = (ms: number, action: () => void) => {
      timers.push(window.setTimeout(() => {
        action();
        steps += 1;
        if (root) {
          root.dataset.tourStep = String(steps);
          root.dataset.tourLastAt = (performance.now() - started).toFixed(1);
        }
      }, ms));
    };
    let wave = 0;
    at(800, () => {
      patch("mina", { status: "speaking", level: reduced ? 0.6 : WAVE[0] });
      if (reduced) return;
      intervals.push(window.setInterval(() => {
        wave += 1;
        patch("mina", { status: "speaking", level: WAVE[wave % WAVE.length] ?? 0.5 });
      }, WAVE_MS));
    });
    at(UPLOAD_AT, () => {
      patch("sora", { status: "uploading", progress: 0 });
      const ticker = window.setInterval(() => {
        const value = clamp01((performance.now() - started - UPLOAD_AT) / UPLOAD_MS);
        patch("sora", { status: "uploading", progress: value });
        if (value >= 1) window.clearInterval(ticker);
      }, UPLOAD_TICK_MS);
      intervals.push(ticker);
    });
    at(3400, () => patch("jordan", { status: "away" }));
    at(UPLOAD_AT + UPLOAD_MS, () => patch("sora", { status: "uploading", progress: 1 }));
    at(UPLOAD_AT + UPLOAD_MS + 200, () => patch("sora", { status: "online" }));
    at(5400, () => patch("theo", { status: "busy" }));
    at(6200, () => {
      intervals.forEach((interval) => window.clearInterval(interval));
      patch("mina", { status: "online" });
    });
    at(LOOP_MS, () => {
      setPresences(INITIAL);
      setRun((previous) => previous + 1);
    });
    return () => {
      timers.forEach((timer) => window.clearTimeout(timer));
      intervals.forEach((interval) => window.clearInterval(interval));
    };
  }, [autoplay, lab, paused, reduced, run, patch]);

  const takeOver = () => { if (autoplay && !lab) setPaused(true); };

  return (
    <main
      ref={rootRef}
      data-demo="avatar-status-ring"
      data-paused={paused ? "true" : "false"}
      className="flex w-full items-center justify-center bg-background p-4 text-foreground"
      style={{ height: "min(100svh, 640px)" }}
      onPointerDownCapture={takeOver}
      onKeyDownCapture={takeOver}
    >
      <section
        aria-label="Design sync"
        className="w-full max-w-[560px] rounded-2xl bg-card p-5 text-card-foreground ring-1 ring-border shadow-[0_16px_40px_-24px_color-mix(in_oklch,var(--color-foreground)_40%,transparent)]"
      >
        <header className="flex items-start justify-between gap-4">
          <div className="min-w-0">
            <p className="truncate text-sm font-medium leading-5">Design sync</p>
            <p className="truncate text-xs leading-4 text-muted-foreground">Weekly · Room 2</p>
          </div>
          <p className="shrink-0 pt-0.5 text-xs tabular-nums leading-4 text-muted-foreground">14:00 – 14:30</p>
        </header>
        <ul className="mt-5 grid grid-cols-4 gap-2">
          {ORDER.map((id, index) => {
            const person = CALL[id];
            const presence = presences[id];
            return (
              <li key={id} className="flex min-w-0 flex-col items-center text-center">
                <AvatarStatusRing
                  src={id === "sora" && broken ? BROKEN_SRC : person.photo}
                  alt={person.name}
                  name={person.name}
                  size={64}
                  status={presence.status}
                  level={presence.level}
                  progress={presence.progress}
                  drawDelay={index * 80}
                  surface="var(--color-card)"
                  tone={id === "jordan" && toned ? { online: "var(--color-chart-3)" } : undefined}
                  ringWidth={id === "theo" && thick ? 4 : undefined}
                  showIcon={id === "theo" && thick ? false : undefined}
                  announce={announceAll}
                  data-person={id}
                />
                <p className="mt-2 max-w-full truncate text-sm font-medium leading-5">{person.name}</p>
                <p data-status-text className="max-w-full truncate text-xs tabular-nums leading-4 text-muted-foreground">{phraseOf(presence)}</p>
              </li>
            );
          })}
        </ul>
        <div className="mt-5 flex items-center justify-between gap-4 border-t border-border pt-4">
          <p className="truncate text-xs leading-4 text-muted-foreground">Also in #design</p>
          <AvatarStatusRingGroup
            items={CHANNEL}
            max={5}
            size={32}
            ringWidth={2}
            surface="var(--color-card)"
            drawDelay={320}
            stagger={80}
            announce={announceAll}
            aria-label="Also in #design"
            className="shrink-0"
          />
        </div>
      </section>
    </main>
  );
}

Dependencies

More by DHxWhy

View all
  • Product Rail Gallery – Fashion Store Hero Section

    Product Rail Gallery – Fashion Store Hero Section

    2.2K
  • Sushi Conveyor Belt Menu – Restaurant Hero Section

    Sushi Conveyor Belt Menu – Restaurant Hero Section

    883
  • Team Lanyard Rail – Meet the Team Section with Flip Badges

    Team Lanyard Rail – Meet the Team Section with Flip Badges

    830
  • Skateboard Deck Rail Gallery – Skate Shop Hero Section

    Skateboard Deck Rail Gallery – Skate Shop Hero Section

    431
  • Sun Moon Dark Mode Theme Toggle

    Sun Moon Dark Mode Theme Toggle

    328
  • Picture Rail Image Gallery – Art Print Shop Hero Section

    Picture Rail Image Gallery – Art Print Shop Hero Section

    268
  • Pendant Lamp Rail Gallery – Lighting Store Hero Section

    Pendant Lamp Rail Gallery – Lighting Store Hero Section

    243
  • World Testimonials Globe – Social Proof Hero Section

    World Testimonials Globe – Social Proof Hero Section

    217