component

Avatar

Displays a user’s profile image, falling back to initials (derived from name) or a generic person icon when no image is provided or the image fails to load. Inherits panel surface props (background, border, radius, shadow, …) so it can blend into any context.

Default

Pass src to render the image. When src is missing or fails to load, the avatar derives initials from name — or renders a user icon when neither is provided.

Ada LovelaceAT
---
// GENERATED from packages/demos/avatar/default.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "md", direction: "row", align: "center" })}>
  <Avatar
    name="Ada Lovelace"
    src="https://i.pravatar.cc/96?u=ada"
    alt="Ada Lovelace"
  />
  <Avatar name="Alan Turing" />
  <Avatar />
</div>

Tone

Every tone value: the semantic tones and the color families. A family tone colors a person without implying a status — hash a name onto one of the families for stable, distinct avatars.

PRNESUWADATECYVIPISLSTSAMA
---
// GENERATED from packages/demos/avatar/tone.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import { stack } from "@pindoba/styled-system/patterns";
---

<div
  class={stack({
    gap: "md",
    direction: "row",
    align: "center",
    flexWrap: "wrap",
  })}
>
  <Avatar name="Primary" tone="primary" />
  <Avatar name="Neutral" tone="neutral" />
  <Avatar name="Success" tone="success" />
  <Avatar name="Warning" tone="warning" />
  <Avatar name="Danger" tone="danger" />
  <Avatar name="Teal" tone="teal" />
  <Avatar name="Cyan" tone="cyan" />
  <Avatar name="Violet" tone="violet" />
  <Avatar name="Pink" tone="pink" />
  <Avatar name="Slate" tone="slate" />
  <Avatar name="Stone" tone="stone" />
  <Avatar name="Sage" tone="sage" />
  <Avatar name="Mauve" tone="mauve" />
</div>

Size

Five sizes (xs, sm, md, lg, xl) matching the button scale — so an avatar and a button of the same size align perfectly.

ALALALALAL
---
// GENERATED from packages/demos/avatar/size.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import { stack } from "@pindoba/styled-system/patterns";
---

<div
  class={stack({
    gap: "md",
    direction: "row",
    align: "center",
    flexWrap: "wrap",
  })}
>
  <Avatar size="xs" name="Ada Lovelace" />
  <Avatar size="sm" name="Ada Lovelace" />
  <Avatar size="md" name="Ada Lovelace" />
  <Avatar size="lg" name="Ada Lovelace" />
  <Avatar size="xl" name="Ada Lovelace" />
</div>

Shape

Circle (default) or square with a rounded corner.

Ada LovelaceAda Lovelace
---
// GENERATED from packages/demos/avatar/shape.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "md", direction: "row", align: "center" })}>
  <Avatar
    shape="circle"
    name="Ada Lovelace"
    src="https://i.pravatar.cc/96?u=ada"
  />
  <Avatar
    shape="square"
    name="Ada Lovelace"
    src="https://i.pravatar.cc/96?u=ada"
  />
</div>

Fallback

Without a src, the avatar falls back to up-to-two uppercase initials derived from name. When name is also missing, a generic icon is rendered.

ALA
---
// GENERATED from packages/demos/avatar/fallback.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "md", direction: "row", align: "center" })}>
  <Avatar name="Ada Lovelace" />
  <Avatar name="A" />
  <Avatar />
</div>

Group

Wrap avatars in a <Group> to get a classic face pile — subsequent avatars overlap, each ringed by the surrounding background so neighbours stay visually distinct. Works for both circle and square shapes and every size.

Ada LovelaceAlan TuringGrace HopperKen Thompson+3
Ada LovelaceAlan TuringGrace Hopper+12
Ada LovelaceAlan TuringGrace Hopper+5
---
// GENERATED from packages/demos/avatar/group.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import Group from "@pindoba/astro-group";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "lg", direction: "column" })}>
  <Group variant="stack">
    <Avatar name="Ada Lovelace" src="https://i.pravatar.cc/96?u=ada" />
    <Avatar name="Alan Turing" src="https://i.pravatar.cc/96?u=alan" />
    <Avatar name="Grace Hopper" src="https://i.pravatar.cc/96?u=grace" />
    <Avatar name="Ken Thompson" src="https://i.pravatar.cc/96?u=ken" />
    <Avatar name="+3" />
  </Group>

  <Group variant="stack">
    <Avatar
      size="lg"
      name="Ada Lovelace"
      src="https://i.pravatar.cc/96?u=ada"
    />
    <Avatar
      size="lg"
      name="Alan Turing"
      src="https://i.pravatar.cc/96?u=alan"
    />
    <Avatar
      size="lg"
      name="Grace Hopper"
      src="https://i.pravatar.cc/96?u=grace"
    />
    <Avatar size="lg" name="+12" />
  </Group>

  <Group variant="stack">
    <Avatar
      shape="square"
      name="Ada Lovelace"
      src="https://i.pravatar.cc/96?u=ada"
    />
    <Avatar
      shape="square"
      name="Alan Turing"
      src="https://i.pravatar.cc/96?u=alan"
    />
    <Avatar
      shape="square"
      name="Grace Hopper"
      src="https://i.pravatar.cc/96?u=grace"
    />
    <Avatar shape="square" name="+5" />
  </Group>
</div>

Status indicator

Avatar no longer ships a built-in status prop. To overlay a presence dot — or any other indicator — wrap the avatar in <Attachment> with placement="bottom-end", anchor="corner", and shape="circle", and pass your indicator through the content slot. This works for any element, not just avatars, and lets you use a colored dot, a <Badge>, an icon, or anything else.

AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
AL
AT
GH
KT
Dennis Ritchie
---
// GENERATED from packages/demos/avatar/status.demo.tsx — edit the source, not this file.
import Avatar from "@pindoba/astro-avatar";
import Attachment from "@pindoba/astro-attachment";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";

type Tone = "success" | "warning" | "danger" | "neutral" | "primary";

type Size = "xs" | "sm" | "md" | "lg";

const sizes = ["xs", "sm", "md", "lg"] as const;
const dotBase = css({
  display: "inline-block",
  borderRadius: "full",
  background: "colorPalette",
  outline: "2px solid",
  outlineColor: "neutral.border.bold",
});
const sizeClass = {
  xs: css({ width: "0.5rem", height: "0.5rem" }),
  sm: css({ width: "0.625rem", height: "0.625rem" }),
  md: css({ width: "0.75rem", height: "0.75rem" }),
  lg: css({ width: "0.875rem", height: "0.875rem" }),
} as Record<Size, string>;
const feedbackClass = {
  primary: css({ colorPalette: "primary" }),
  success: css({ colorPalette: "success" }),
  warning: css({ colorPalette: "warning" }),
  danger: css({ colorPalette: "danger" }),
  neutral: css({ colorPalette: "neutral" }),
} as Record<Tone, string>;
const dotClass = (size: Size, tone: Tone) =>
  `${dotBase} ${sizeClass[size]} ${feedbackClass[tone]}`;
const people = [
  { name: "Ada Lovelace", tone: "success" },
  { name: "Alan Turing", tone: "warning" },
  { name: "Grace Hopper", tone: "danger" },
  { name: "Ken Thompson", tone: "neutral" },
  {
    name: "Dennis Ritchie",
    tone: "primary",
    src: "https://i.pravatar.cc/96?u=dennis",
  },
] as Array<{ name: string; tone: Tone; src?: string }>;
---

<div class={stack({ gap: "lg", direction: "column" })}>
  {sizes.map((size) => (
    <div
      class={stack({
        gap: "md",
        direction: "row",
        align: "center",
        flexWrap: "wrap",
      })}
    >
      {people.map((person) => (
        <Attachment placement="bottom-end" anchor="corner" shape="circle">
          <span slot="content" class={dotClass(size, person.tone)}></span>
          <Avatar size={size} name={person.name} src={person.src} />
        </Attachment>
      ))}
    </div>
  ))}
  {sizes.map((size) => (
    <div
      class={stack({
        gap: "md",
        direction: "row",
        align: "center",
        flexWrap: "wrap",
      })}
    >
      {people.map((person) => (
        <Attachment
          placement="bottom-end"
          anchor="corner"
          shape="rect"
          hugCorners
        >
          <span slot="content" class={dotClass(size, person.tone)}></span>
          <Avatar
            shape="square"
            size={size}
            name={person.name}
            src={person.src}
          />
        </Attachment>
      ))}
    </div>
  ))}
</div>
  • Components
  • Blocks