# Avatar

A person or thing as a circle: initials, an icon, or a picture, in six sizes.

Block: `smbk-avatar`. Status: candidate. Figma: the Figma file, https://www.figma.com/community/file/1688324308358870630. Desktop and mobile: differ by presentation only.

## Options

| Axis | Values | Default | Meaning |
|---|---|---|---|
| `size` | `2xs`, `xs`, `sm`, `md`, `lg`, `xl` | `xl` |  |
| `tone` | `default`, `brand`, `inverse` | `default` | Default sits on the raised surface; brand on the brand fill; inverse on the inverse fill. |
| `type` | `initials`, `icon`, `image` | `initials` | What fills the circle. Figma calls the image type "Avatar". |

Parts: `smbk-avatar__initials`, `smbk-avatar__icon`, `smbk-avatar__image`

## Markup

```html
<span
  class="smbk-avatar smbk-avatar--size-xl smbk-avatar--tone-default smbk-avatar--type-initials"
  role="img"
  aria-label="Maya Chen"
>
  <span class="smbk-avatar__initials" aria-hidden="true">MC</span>
</span>
```

## React

```tsx
import { Avatar } from './design-system/components/avatar/avatar.js';

<Avatar size="xl" tone="default" type="initials" icon="UsersThree" alt="Maya Chen">MC</Avatar>
```

## Stylesheet

```css
/* smbk-avatar — Avatar. Figma "Avatar" 962:62.
 * Sizes are bound to primitive size steps in Figma; so here. Initials take a
 * text style per size, as Figma binds them: the label styles up to the medium
 * avatar, then Body LG, then Heading 2XS at the largest. */

.smbk-avatar {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--smbk-size-88);
  height: var(--smbk-size-88);
  overflow: hidden;
  border: var(--smbk-border-width-hairline) solid var(--smbk-color-border-rim-subtle);
  border-radius: var(--smbk-radius-full);
  background: var(--smbk-color-surface-raised);
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-heading-2xs-font-family);
  font-size: var(--smbk-typography-heading-2xs-font-size);
  font-weight: var(--smbk-typography-heading-2xs-font-weight);
  line-height: var(--smbk-typography-heading-2xs-line-height);
  letter-spacing: var(--smbk-typography-heading-2xs-letter-spacing);
  -webkit-user-select: none;
  user-select: none;
}

.smbk-avatar__icon {
  font-size: var(--smbk-size-icon-2xl);
}

.smbk-avatar__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---- tone. The default tone is the block's own look above. ---- */

.smbk-avatar--tone-brand {
  background: var(--smbk-color-surface-brand);
  color: var(--smbk-color-text-on-brand);
}

.smbk-avatar--tone-inverse {
  background: var(--smbk-color-surface-inverse);
  color: var(--smbk-color-text-inverse);
}

/* ---- size ---- */

.smbk-avatar--size-lg {
  width: var(--smbk-size-64);
  height: var(--smbk-size-64);
  font-family: var(--smbk-typography-body-lg-font-family);
  font-size: var(--smbk-typography-body-lg-font-size);
  font-weight: var(--smbk-typography-body-lg-font-weight);
  line-height: var(--smbk-typography-body-lg-line-height);
  letter-spacing: var(--smbk-typography-body-lg-letter-spacing);
}

.smbk-avatar--size-lg .smbk-avatar__icon { font-size: var(--smbk-size-icon-xl); }

.smbk-avatar--size-md {
  width: var(--smbk-size-40);
  height: var(--smbk-size-40);
  font-family: var(--smbk-typography-label-lg-font-family);
  font-size: var(--smbk-typography-label-lg-font-size);
  font-weight: var(--smbk-typography-label-lg-font-weight);
  line-height: var(--smbk-typography-label-lg-line-height);
  letter-spacing: var(--smbk-typography-label-lg-letter-spacing);
}

.smbk-avatar--size-md .smbk-avatar__icon { font-size: var(--smbk-size-icon-lg); }

.smbk-avatar--size-sm {
  width: var(--smbk-size-32);
  height: var(--smbk-size-32);
  font-family: var(--smbk-typography-label-md-font-family);
  font-size: var(--smbk-typography-label-md-font-size);
  font-weight: var(--smbk-typography-label-md-font-weight);
  line-height: var(--smbk-typography-label-md-line-height);
  letter-spacing: var(--smbk-typography-label-md-letter-spacing);
}

.smbk-avatar--size-sm .smbk-avatar__icon { font-size: var(--smbk-size-icon-md); }

.smbk-avatar--size-xs {
  width: var(--smbk-size-24);
  height: var(--smbk-size-24);
  font-family: var(--smbk-typography-label-sm-font-family);
  font-size: var(--smbk-typography-label-sm-font-size);
  font-weight: var(--smbk-typography-label-sm-font-weight);
  line-height: var(--smbk-typography-label-sm-line-height);
  letter-spacing: var(--smbk-typography-label-sm-letter-spacing);
}

.smbk-avatar--size-xs .smbk-avatar__icon { font-size: var(--smbk-size-icon-sm); }

.smbk-avatar--size-2xs {
  width: var(--smbk-size-20);
  height: var(--smbk-size-20);
  font-family: var(--smbk-typography-label-sm-font-family);
  font-size: var(--smbk-typography-label-sm-font-size);
  font-weight: var(--smbk-typography-label-sm-font-weight);
  line-height: var(--smbk-typography-label-sm-line-height);
  letter-spacing: var(--smbk-typography-label-sm-letter-spacing);
}

.smbk-avatar--size-2xs .smbk-avatar__icon { font-size: var(--smbk-size-icon-xs); }
```

## Tokens it reads

```json
{
  "size": {
    "20": {
      "$type": "dimension",
      "$value": "20px",
      "$description": "Raw size step, 20 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "24": {
      "$type": "dimension",
      "$value": "24px",
      "$description": "Raw size step, 24 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "32": {
      "$type": "dimension",
      "$value": "32px",
      "$description": "Raw size step, 32 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "40": {
      "$type": "dimension",
      "$value": "40px",
      "$description": "Raw size step, 40 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "64": {
      "$type": "dimension",
      "$value": "64px",
      "$description": "Raw size step, 64 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "88": {
      "$type": "dimension",
      "$value": "88px",
      "$description": "Raw size step, 88 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "icon": {
      "2xl": {
        "$type": "dimension",
        "$value": "{{size.40}}",
        "$description": "Icon box, 2× large."
      },
      "xl": {
        "$type": "dimension",
        "$value": "{{size.32}}",
        "$description": "Icon box, extra large."
      },
      "lg": {
        "$type": "dimension",
        "$value": "{{size.24}}",
        "$description": "Icon box, large."
      },
      "md": {
        "$type": "dimension",
        "$value": "{{size.20}}",
        "$description": "Icon box, medium."
      },
      "sm": {
        "$type": "dimension",
        "$value": "{{size.16}}",
        "$description": "Icon box, small."
      },
      "xs": {
        "$type": "dimension",
        "$value": "{{size.12}}",
        "$description": "Icon box, extra small."
      }
    }
  },
  "border-width": {
    "hairline": {
      "$type": "dimension",
      "$value": "{{border-width.1}}",
      "$description": "Thin lines: dividers and almost every edge."
    }
  },
  "color": {
    "border": {
      "rim-subtle": {
        "$type": "color",
        "$value": "{{color.alpha.white.20}}",
        "$description": "A fainter light rim."
      }
    },
    "surface": {
      "raised": {
        "$type": "color",
        "$value": "{{color.grey.50}}",
        "$description": "One floor above default: popovers, raised panels."
      },
      "brand": {
        "$type": "color",
        "$value": "{{color.red.600}}",
        "$description": "Brand-red surface: closers, highlights."
      },
      "inverse": {
        "$type": "color",
        "$value": "{{color.grey.850}}",
        "$description": "The opposite surface: tooltips, dark chips."
      }
    },
    "text": {
      "default": {
        "$type": "color",
        "$value": "{{color.grey.900}}",
        "$description": "Main text."
      },
      "on-brand": {
        "$type": "color",
        "$value": "{{color.grey.50}}",
        "$description": "Text on the brand surface."
      },
      "inverse": {
        "$type": "color",
        "$value": "{{color.grey.50}}",
        "$description": "Text on the opposite surface."
      }
    }
  },
  "radius": {
    "full": {
      "$type": "dimension",
      "$value": "{{radius.9999}}",
      "$description": "Capsule: pills, chips, switches."
    }
  },
  "typography": {
    "heading-2xs": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Funnel Display, Funnel Display Fallback, system-ui, sans-serif",
        "fontSize": {
          "min": "18px",
          "max": "24px"
        },
        "fontWeight": 400,
        "lineHeight": 1.2,
        "letterSpacing": "0px"
      }
    },
    "body-lg": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "20px",
        "fontWeight": 400,
        "lineHeight": 1.5,
        "letterSpacing": "0px"
      }
    },
    "label-lg": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "16px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label LG: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "label-md": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "14px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label MD: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "label-sm": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "12px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label SM: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    }
  }
}
```

## Purpose

A circle that stands for a person, a team or a thing: their picture when there is one, their initials when there is not, or an icon when it is not a person. Six sizes cover a chip's corner up to a profile header.

## Anatomy

- The block, a circle with a faint highlight edge, clipping its content.
- One of three fills: the initials part, the icon part, or the image part. Initials are set in the label styles in the small sizes and grow to the body and heading styles in the large ones.

## When to use

- Beside a name in a list, a comment, a card.
- Inside a chip that stands for a person.
- As the main image of a profile.

## When not to use

- For a logo. Logos are not circles.
- For decoration without a subject.

## Behavior

It is inert; wrap it in a link or a button when it should do something.

A picture that fails to load gives way to the initials, or to the icon when there are none, named by the same alternative text, so the circle never shows the browser's broken-picture mark. A picture that failed before the page's script ran is caught when it runs; without script the browser's own mark shows. A new address is tried afresh.

## Accessibility

### What it does for you

- Initials are always hidden from assistive technology, because they read as letters, not as a name. Given an alternative text, the avatar becomes one image named by it, so the name is read instead.
- An icon avatar is decorative unless labeled.

### What you must do

- Give an image avatar an alternative text describing the subject, or empty text when the name is written right beside it.
- Label an icon avatar when it means something, since it is decorative otherwise.

### How to test

- With a screen reader, an image avatar is read as its alternative text, an initials avatar with no alternative text is skipped, and one with an alternative text is read as one image by that name.
- When the name is written beside the avatar, the avatar adds nothing to what is read.
- Tab past it: the avatar takes no focus.

## Usage rules

### Do

- Write the name beside a small avatar and leave its alternative text empty, so the name is read once.
- Use the default tone for people and the brand tone for the product itself.

### Don't

- Put more than two or three letters in the initials.
- Stretch it. It is square by its size.
