webdevpuneet.com

Avatar with Status — Online Presence Dot Snippet

Avatar with Status · Cards · Plain HTML, CSS & JS · Live preview

CategoryCards

Copy & paste

Source Code

<div class="row">
  <span class="avatar online" role="img" aria-label="Maya — online">
    <img src="https://i.pravatar.cc/120?img=47" alt="">
    <span class="dot"></span>
  </span>

  <span class="avatar away" role="img" aria-label="Leo — away">
    <img src="https://i.pravatar.cc/120?img=12" alt="">
    <span class="dot"></span>
  </span>

  <span class="avatar busy" role="img" aria-label="Ada — busy">
    <img src="https://i.pravatar.cc/120?img=32" alt="">
    <span class="dot"></span>
  </span>

  <span class="avatar offline" role="img" aria-label="Sam — offline">
    <span class="initials">SK</span>
    <span class="dot"></span>
  </span>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Presence dot for online, away, busy, and offline states
Dot border matches the page background for a clean "cut-out" look
Pulsing green ring on the online state (transform/opacity, GPU-friendly)
Busy uses a distinct bar shape, not color alone (accessibility)
Image avatar with a graceful initials fallback for missing photos
Status driven by a single class — el.className = "avatar " + status
role="img" + aria-label announce name and status together
Empty img alt avoids double screen-reader announcement
Easy to resize and re-theme; ready to wire to live presence data
Export as HTML file, React JSX, or React + Tailwind CSS

About this UI Snippet

Avatar with Status — Presence Dot, Pulsing Online Ring & Initials Fallback

Screenshot of the Avatar with Status snippet rendered live

An avatar with a status indicator is one of the most-searched UI snippets because every chat, team, dashboard, and collaboration app needs to show whether a person is online, away, busy, or offline at a glance — stack several into an avatar group or list them in a team presence list. This snippet is a complete presence avatar set: a circular avatar (photo or initials fallback, as on the profile card), a color-coded status dot in the corner, a pulsing ring for the online state, and a distinct shape for "busy" — all done with pure CSS so the status is driven entirely by a single class.

Positioning the status dot correctly

The status dot is an absolutely positioned .dot element pinned to the bottom-right of the avatar (right: 1px; bottom: 1px). The detail that makes it look professional is the border: border: 3px solid #0f172a where that color matches the page background. This creates a "cut-out" effect — the dot appears to punch a hole through the avatar's edge rather than sitting on top of it, which is exactly how Slack, Discord, and Teams render presence dots. If you place an avatar on a different background, you change the dot's border color to match that surface. The avatar uses overflow: visible so the dot (and its pulse) can extend slightly past the circular edge.

Color-coding the four states

Presence is communicated by both position and color. A single class on the avatar (.online, .away, .busy, .offline) sets the dot color: green for online, amber for away, red for busy, gray for offline. These are the conventional presence colors users already recognize, so the meaning is instant. Because the state is a class, changing someone's status in code is one line — el.className = 'avatar ' + status — which maps perfectly to a real app where presence comes from a websocket or polling.

The pulsing online ring

To make "online" feel alive, the online dot has an ::after pseudo-element — a green ring that scales up and fades out on a 1.8s loop (@keyframes pulse). It starts small and slightly transparent, then expands to 1.8× and fades to zero, like a radar ping or a heartbeat. This subtle animation draws the eye to active users without being distracting, and because it only animates transform and opacity, it is GPU-cheap even with many avatars on screen. Only the online state pulses; the others are static, which reinforces that online means "active right now."

Not relying on color alone (the busy shape)

Color-only status indicators fail for color-blind users — red (busy) and green (online) are the classic confusable pair. This snippet addresses that for the most critical distinction by giving "busy" a different *shape*: its dot shows a white horizontal bar (a "do not disturb" minus), so busy is distinguishable from online by form, not just hue. This is a small but meaningful accessibility improvement; you could extend the same idea with a clock glyph for away and a hollow ring for offline so every state is identifiable without color.

The initials fallback

Not every user has a photo, so the fourth avatar demonstrates an initials fallback: instead of an <img>, it shows centered initials ("SK") on a neutral background. This is the standard graceful degradation for missing avatars and is handled purely with markup and CSS — no broken image icon, no layout shift. In a real app you would render initials when there is no avatarUrl, often with a background color derived from the user's name so each person gets a consistent, distinct color.

Accessibility

Each avatar is wrapped in a role="img" element with an aria-label that includes both the name and the status ("Maya — online"), so screen readers announce the person and their presence together. The <img> has an empty alt because the labeled wrapper already provides the accessible name (avoiding a double announcement). This is the correct pattern for an image-plus-status composite: label the whole unit, not just the photo. Combined with the busy shape distinction, the component conveys status to users who cannot perceive the colors.

Customizing the avatars

Resize by changing the avatar width/height and scaling the dot proportionally (keep the dot roughly a quarter of the avatar size). Re-theme the status colors to your brand while keeping them conventional enough to be understood. Change the dot border color to match whatever background the avatar sits on. To stack avatars into a group, overlap them with negative margins and a background-colored ring on each. To add a tooltip with the full status text on hover, wrap the name/status in a title attribute or a CSS tooltip. The whole component is class-driven, so wiring it to live presence data is just updating the avatar's class.

Step by step

How to Use

  1. 1
    Copy an avatarEach avatar is a .avatar span with an <img> (or .initials), a .dot, and a status class (online/away/busy/offline). Keep the role="img" and aria-label.
  2. 2
    Match the dot border to the backgroundSet the .dot border color to the surface the avatar sits on, so the dot looks cut out of the avatar edge. Change it per background.
  3. 3
    Set status from dataChange the status in code with one line: el.className = "avatar " + status. Wire this to your presence websocket or API.
  4. 4
    Use initials when there is no photoRender a .initials span instead of an <img> for users without an avatar; optionally derive the background color from their name.
  5. 5
    Keep status distinguishable without colorThe busy state uses a bar shape, not just red. Extend the idea (clock for away, etc.) so color-blind users can tell states apart.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Chat and messaging apps
Show whether contacts are online, away, busy, or offline next to their avatar — the core presence indicator of any chat UI.
Team dashboards and member lists
Indicate who is active in a project, support queue, or org chart so users know who to reach right now.
Collaboration and call apps
Display availability for meetings and calls, using busy/do-not-disturb to signal who should not be interrupted.
Learn the cut-out dot trick
See why matching the dot border to the background makes the presence indicator look punched through the avatar edge.
Color-blind-friendly status
Learn to distinguish states by shape (the busy bar) as well as color, so presence is readable without relying on hue.
Class-driven presence component
Wire live websocket presence to a single class change, with an initials fallback for users who have no profile photo.

Got questions?

Frequently Asked Questions

Make the avatar position: relative and add an absolutely positioned dot pinned to the bottom-right corner. Give the dot a border whose color matches the page background so it looks cut out of the avatar edge, and set its background color from a status class (green online, amber away, red busy, gray offline).

The matching border creates a "cut-out" effect — the dot appears to punch through the avatar's edge rather than float on top, which is how Slack, Discord, and Teams render presence. On a different background, change the dot border to match that surface.

Status is a single class on the avatar, so set el.className = "avatar " + status where status is online, away, busy, or offline. This maps directly to live presence from a websocket or polling — update the class when the server sends a new status.

Each avatar has a role="img" and an aria-label that includes the name and status, so screen readers announce both. For visual users, the busy state uses a distinct bar shape (not just red) so it is distinguishable from green online by form; you can extend the idea to the other states.

Render an .initials span instead of an <img>. The avatar centers the initials on a neutral background, avoiding a broken-image icon. In a real app, derive the background color from the user's name so each person gets a consistent color.

Yes. Click "JSX" for a React component or "Tailwind" for a React + Tailwind version. In React, pass the status as a prop and apply it as a class, render an <img> or initials based on whether an avatar URL exists, and update the status from your presence state.