Skip to content
cennge-ui
GitHubv0.3.1, changelog

Avatar

A person or a project as a picture, or as initials when there is no picture; overlapping in a group with a counter.

Cenngegithub.com/Cennge
CUASPC+2
  • CU
    cennge-uiReact UI library
  • AS
    ai-niche-scoutFinds niches worth building for
  • PC
    payload-cacheFastAPI cache service
  • SS
    spredo-crypto-screenerCrypto screener
  • PS
    playwright-msi-scraperScraper on Playwright
  1. With src, the picture shows once it has loaded. If loading takes over 300 ms, the initials show meanwhile; if it fails, they stay.
  2. Initials are the first letters of the first and last word of name; dashes, dots and underscores split words too, so ai-niche-scout is AS.
  3. AvatarGroup shows the first max avatars and a +N counter for the rest.
Live: the picture loads after the page; the rest is initials.

Field marks

Import
import { Avatar, AvatarGroup } from "cennge-ui";
Size
1.1 KB gzip for this import, its dependencies aside
Pattern
Radix Avatar: an <img> once it has loaded, otherwise the fallback
SSR
Rendered on the server in the Next.js check; hydrates without a warning
Alt text
From alt, otherwise name
Fallback
Initials from name, or your own node; after 300 ms when there is a picture
Tests
Unit tests

When to use#

An Avatar shows who or what something belongs to: the account in a header, the author of a comment, the owner of a repository. The name does two jobs: it is the picture's alt text, and without a picture it becomes the initials, set on one of seven color tints.

Similar#

  • Indicator puts a status dot or a count on the avatar's corner; the two go together.
  • Skeleton holds the avatar's place while the account itself is still loading. An Avatar waiting for its picture already shows initials.

Picture, initials or your own#

A single word gives its first two letters; several give the first letter of the first and last. fallback replaces the initials with anything, such as an icon for a signed-out visitor.

CEPC
fallback.tsx
import { Avatar } from "cennge-ui";

function PersonIcon() {
  return (
    <svg viewBox="0 0 24 24" className="size-5" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
      <circle cx="12" cy="8.5" r="3.75" />
      <path d="M4.75 20c.9-3.6 3.75-5.75 7.25-5.75s6.35 2.15 7.25 5.75" strokeLinecap="round" />
    </svg>
  );
}

export default function AvatarFallback() {
  return (
    <div className="flex flex-wrap items-center gap-4">
      {/* The picture, once it loads; alt text from name. */}
      <Avatar src="/avatar.svg" name="Cennge" size="lg" />
      {/* No picture: the first two letters of a single word. */}
      <Avatar name="Cennge" size="lg" />
      {/* First and last word: payload-cache is PC. */}
      <Avatar name="payload-cache" color="success" size="lg" />
      {/* Your own fallback instead of initials, e.g. for a signed-out visitor. */}
      <Avatar fallback={<PersonIcon />} size="lg" />
    </div>
  );
}

Sizes and shapes#

Four sizes, from 32 to 64 pixels. Avatars are round by default; radius="md" reads as a project or an organisation rather than a person.

ASASASAS
sizes.tsx
import { Avatar, type AvatarSize } from "cennge-ui";

const sizes: AvatarSize[] = ["sm", "md", "lg", "xl"];

export default function AvatarSizes() {
  return (
    <div className="flex flex-col gap-5">
      <div className="flex flex-wrap items-center gap-4">
        {sizes.map((size) => (
          <Avatar key={size} src="/avatar.svg" name="Cennge" size={size} />
        ))}
      </div>
      {/* Round for people, a softer square for projects. */}
      <div className="flex flex-wrap items-center gap-4">
        {sizes.map((size) => (
          <Avatar key={size} name="ai-niche-scout" color="info" radius="md" size={size} />
        ))}
      </div>
    </div>
  );
}

A group with a counter#

AvatarGroup overlaps its avatars and, past max, adds a counter of the rest. isBordered draws a ring in the page colour around each avatar so the overlaps stay apart. The group's size sets only the counter's size, so give it the same size as the avatars.

CUASPC+2
CUASPCSS+1
group.tsx
import { Avatar, AvatarGroup, type CenngeColor } from "cennge-ui";

const repositories: { name: string; color: CenngeColor }[] = [
  { name: "cennge-ui", color: "primary" },
  { name: "ai-niche-scout", color: "info" },
  { name: "payload-cache", color: "success" },
  { name: "spredo-crypto-screener", color: "warning" },
  { name: "playwright-msi-scraper", color: "secondary" },
];

export default function RepositoryStack() {
  return (
    <div className="flex flex-col gap-5">
      <AvatarGroup max={3}>
        {repositories.map((repository) => (
          <Avatar key={repository.name} name={repository.name} color={repository.color} isBordered />
        ))}
      </AvatarGroup>
      {/* The group's size is the counter's: give it the avatars' size. */}
      <AvatarGroup max={4} size="lg">
        {repositories.map((repository) => (
          <Avatar key={repository.name} name={repository.name} color={repository.color} size="lg" isBordered />
        ))}
      </AvatarGroup>
    </div>
  );
}

With a status#

Wrap an avatar in an Indicator with shape="circle": the dot moves in from the empty corner onto the edge of the circle. Its label is what screen readers hear.

OnlinePC3 failed CI runs
status.tsx
import { Avatar, Indicator } from "cennge-ui";

export default function AvatarStatus() {
  return (
    <div className="flex flex-wrap items-center gap-6">
      <Indicator shape="circle" color="success" label="Online">
        <Avatar src="/avatar.svg" name="Cennge" size="lg" />
      </Indicator>
      <Indicator shape="circle" content={3} label="3 failed CI runs">
        <Avatar name="payload-cache" color="success" size="lg" />
      </Indicator>
    </div>
  );
}

Server rendering#

An avatar without src is rendered with its initials on the server. One with src is rendered empty: the picture is shown only after the browser has loaded it, and the initials only if it has not loaded within 300 ms, so a cached picture does not flash letters first.

Props#

Avatar#

PropTypeDefault
src
string
–
name
stringUsed for the alt text and the initials fallback.
–
alt
string
–
fallback
React.ReactNodeShown while the image loads or when it fails. Defaults to the initials.
–
size
"sm""md""lg""xl"
"md"
radius
"none""sm""md""lg""full"
"full"
color
"default""primary""secondary""success""warning""danger""info"Fallback colour.
"default"
isBordered
booleanRing in the page colour; useful in overlapping groups.
–

Also takes every attribute of <span>, except color, which mean something else here.

AvatarGroup#

PropTypeDefault
max
numberShow at most this many avatars, then a "+N" counter.
–
size
"sm""md""lg""xl"
"md"

Also takes every attribute of <div>.