Avatar — visual reference

Variants (initials, medium)

variants DR KM EL SA

Sizes (accent)

sizes S M L XL

Image content

image Sample user Sample user Sample user Sample user

Icon content

icon

  
/*
 * Avatar — element
 *
 * User/entity representation. Supports initials, image, or icon content.
 * CSS-only — no JavaScript, no tweak slots.
 *
 *   <span class="avatar -accent">KM</span>
 *   <span class="avatar -l"><img src="/u.jpg" alt="Kazimir Malevich" /></span>
 *   <span class="avatar -accent"><svg aria-hidden="true">…</svg></span>
 */

@layer malevich.components {
  .avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;

    /* Default size = medium */
    width: var(--size-control-m);
    height: var(--size-control-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);
    border-radius: var(--radius-avatar);

    /* Initials typography — defaults to body-support. */
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    text-transform: uppercase;
    overflow: hidden;
    user-select: none;
  }

  /* Image content stretches edge-to-edge. */
  .avatar > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  /* Icon content (SVG) inherits avatar text color, sized via em. */
  .avatar > svg {
    width: 60%;
    height: 60%;
    display: block;
    fill: currentColor;
  }

  /* ----- Variants ----- */

  .avatar.-accent {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
  }

  /* Bone — warm raised surface */
  .avatar.-bone {
    background-color: var(--color-surface-float);
    color: var(--color-ink-strong);
  }

  .avatar.-neutral {
    background-color: var(--color-border-muted);
    color: var(--color-ink-strong);
  }

  /* ----- Sizes ----- */

  .avatar.-s {
    width: var(--size-control-s);
    height: var(--size-control-s);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .avatar.-l {
    width: var(--size-control-l);
    height: var(--size-control-l);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  .avatar.-xl {
    width: var(--size-control-xl);
    height: var(--size-control-xl);
    font-family: var(--font-display-title-family);
    font-size: var(--font-display-title-size);
    font-weight: var(--font-display-title-weight);
    line-height: var(--font-display-title-line-height);
    letter-spacing: var(--font-display-title-letter-spacing);
  }
}
This component is pure CSS — no JavaScript required.
# Avatar — AGENTS.md

> Auto-generated from `avatar.docs.md` + the modifier applicability matrix.
> Edit those source files; this file regenerates on build.

## Identity

- **Component:** `avatar`
- **Layer:** elements
- **Status:** stable
- **Last updated:** 2026-05-17

## Summary

Use an avatar wherever you need to put a face (or stand-in) next to a

## Variants

| Variant   | Class               | Use for                                  |
|-----------|---------------------|------------------------------------------|
| Default   | `.avatar`           | Neutral fallback (raised surface)        |
| Accent    | `.avatar.-accent`   | Self, current user, highlight            |
| Bone      | `.avatar.-bone`     | Warm fallback, secondary identity        |
| Neutral   | `.avatar.-neutral`  | Disabled, archived, system               |

## Modifier applicability

Per ADR-0007. Modifiers attach via `data-{category}="value"` attributes.

| Category | Accepts |
|---|---|
| `background` | — |
| `surface` | `flat`, `elevated` |
| `effect` | `ring` |
| `shader` | — |
| `rhythm` | — |
| `motion` | any value |
| `behavior` | — |

## Anatomy

**Initials:**

```html
<span class="avatar -accent">KM</span>
<span class="avatar -bone -l">DR</span>
```

**Image:**

```html
<span class="avatar -l">
  <img src="/avatar.jpg" alt="Kazimir Malevich" />
</span>
```

**Icon (placeholder for Phase 4 morph-icons):**

```html
<span class="avatar -accent">
  <svg aria-hidden="true" viewBox="0 0 24 24">…</svg>
</span>
```

The CSS handles all three content types: initials center via flexbox,
`<img>` fills the circle with `object-fit: cover`, and `<svg>` shrinks
to 60% of the avatar so it reads as an icon rather than a background.

## Tokens consumed

- `color.accent`, `color.surface-raised`, `color.surface-float`,
  `color.border-muted`
- `color.ink-strong`, `color.ink-inverse`
- `font.caption`, `font.body-support`, `font.body-regular`,
  `font.heading-block` (for `-xl` initials)
- `radius.avatar` (9999px, full pill)
- `size-control.s`, `size-control.m`, `size-control.l`, `size-control.xl`

Tier 3 (component-specific): none.

## Accessibility contract

- **Initials avatars** — the parent context must supply the full name
  (tooltip, adjacent text, or `aria-label` on the wrapping link).
  Initials alone are not an accessible name.
- **Image avatars** — `<img alt="…">` is mandatory; the alt should
  describe the person (e.g. `"Kazimir Malevich"`), not the visual
  (`"profile picture"`).
- **Icon avatars** — `aria-hidden="true"` on the `<svg>`; the label
  comes from context.

## Guidance

### Do

- Use the same size for every avatar in a list — mixed sizes break
  rhythm.
- Provide a real `alt` for image avatars; describe who, not what.
- Use `-accent` sparingly — it's the "this is you" highlight, not a
  decorative color.

### Don't

- Don't bake the user's name into the avatar's class or data attribute;
  use real DOM text or `aria-label` on the wrapping link.
- Don't put interactive elements inside the avatar; wrap the avatar in
  a link or button instead.
- Don't override the radius — avatars are always full circles in v1.0.