Avatar
A data-display component that shows an image, or initials derived from text when there is no
image (or while it loads). Supports a title / subtitle column for list and profile UIs.
The examples are organised by layer: the class reference is the standalone
@oriui/css layer, and the Framework API is the @oriui/vue component. Every
example is live — flip its code between HTML (the standalone classes, also your htmx / Astro / Svelte /
plain-HTML usage), Vue; HTML is the default.
Classes
An avatar is a block class plus single-class token utilities — one class repoints one token; no
separate base class is needed. The Vue props in Framework API mirror these — font
size and the titled layout are derived from size and title / subtitle. There is no variant;
an optional color tints the initials backdrop.
| Class | Type | Description |
|---|---|---|
ori-avatar | Block | Required base class. |
ori-color_* | Color | primary · secondary · success · warn · danger · info · surface · background — tints the initials backdrop |
ori-avatar_* (size) | Size | xs · sm · md · lg · xl · xxl |
ori-size-action-space_* | Size | adds margin around the avatar when spaced is set |
ori-size-radius_* | Radius | zero · xs · sm · md · lg · xl · rounded |
ori-font-size_* | Font | scales the initials text with the avatar size |
ori-avatar__image · ori-avatar__backdrop · ori-avatar__text · ori-avatar__title · ori-avatar__subtitle | Part | image / initials fallback / text column / title / subtitle |
ori-avatar_inline · ori-avatar_titled · ori-avatar_reverse | Layout | inline flow · title+subtitle layout · reversed image/text order |
Image & initials
src (and any other image attribute) falls through via $attrs to the <img> element. When no
src is present — or while the image loads — the initials backdrop is shown instead, computing up
to two letters from the first two words of text.
<!-- with image — bare .ori-avatar is already lg + rounded (defaults baked in) -->
<div class="ori-avatar">
<img class="ori-avatar__image" src="/portrait.jpg" alt="Marcus Tullius Cicero" />
</div>
<!-- initials fallback: backdrop is aria-hidden -->
<div class="ori-avatar">
<div class="ori-avatar__backdrop" aria-hidden="true">MT</div>
</div>
Colors
An optional color tints the initials backdrop using the standard semantic token. Has no effect
when an image is showing.
<div class="ori-avatar ori-color_danger">
<div class="ori-avatar__backdrop" aria-hidden="true">D</div>
</div>
Sizes
xs → xxl. The size drives the box dimensions (ori-avatar_*) and the initials scale
(ori-font-size_*). Default is lg.
<div class="ori-avatar ori-avatar_sm ori-font-size_sm">
<div class="ori-avatar__backdrop" aria-hidden="true">S</div>
</div>
<div class="ori-avatar ori-avatar_xl ori-font-size_xl">
<div class="ori-avatar__backdrop" aria-hidden="true">EL</div>
</div>
Radius
From zero (square) to the default rounded (full pill / circle).
<div class="ori-avatar ori-size-radius_zero">
<div class="ori-avatar__backdrop" aria-hidden="true">Z</div>
</div>
With title & subtitle
Pass title and/or subtitle to show a text column beside the image or initials. The root
element switches to max-content width via ori-avatar_titled.
<!-- ori-avatar_titled activates the text column layout -->
<div class="ori-avatar ori-avatar_titled">
<img class="ori-avatar__image" src="/portrait.jpg" alt="Marcus Tullius Cicero" />
<div class="ori-avatar__text">
<div class="ori-avatar__title">Marcus Tullius Cicero</div>
<div class="ori-avatar__subtitle">statesman · lawyer · writer · orator</div>
</div>
</div>
Reversed
reverse flips the layout so the text column appears before the image.
<div class="ori-avatar ori-avatar_titled ori-avatar_reverse ori-color_primary">
<div class="ori-avatar__text">
<div class="ori-avatar__title">Ada Lovelace</div>
<div class="ori-avatar__subtitle">mathematician</div>
</div>
<div class="ori-avatar__backdrop" aria-hidden="true">AL</div>
</div>
Inline
inline renders the avatar as inline-flex with a small margin, so it flows inside a sentence or
a tag list.
<div class="ori-avatar ori-avatar_inline ori-avatar_xs ori-font-size_xs">
<div class="ori-avatar__backdrop" aria-hidden="true">AL</div>
</div>
Spaced
spaced adds padding around the avatar via ori-size-action-space, useful when the avatar sits
inside a container that provides no gap of its own.
<div class="ori-avatar ori-size-action-space_lg">
<div class="ori-avatar__backdrop" aria-hidden="true">AL</div>
</div>
Common patterns
A user-list row and a comment header — the everyday compositions.
<ul style="display: flex; flex-direction: column; gap: 0.75rem; list-style: none; padding: 0">
<li>
<div class="ori-avatar ori-avatar_titled">
<img class="ori-avatar__image" src="/portrait.jpg" alt="Marcus Tullius Cicero" />
<div class="ori-avatar__text">
<div class="ori-avatar__title">Marcus Tullius Cicero</div>
<div class="ori-avatar__subtitle">Admin</div>
</div>
</div>
</li>
</ul>
Accessibility
The accessibility contract holds across every layer — the standalone classes and the Vue component render the same attributes.
- The
<img>altis always set — to thetextprop value, or''(empty, decorative) whentextis omitted. Do not pass a separatealtvia$attrs; it will be overridden. - The initials backdrop is
aria-hidden="true"— it is a visual fallback, not semantic content. - The
<img>is revealed only after theloadevent fires (v-show), preventing a flash of a broken-image icon while the initials are still visible. - There is no interactive behaviour; the component has no keyboard contract of its own. Wrap it in a
<button>or<a>when it needs to be activatable, and supply anaria-labelon the wrapper.
| Attribute | Element | Notes |
|---|---|---|
alt (from text) | <img> | Set automatically; omit alt in $attrs — it will be replaced. |
aria-hidden="true" | __backdrop | Initials are decorative; screen readers read the image alt. |
Framework API
The props, events, and slots of the Vue component. The standalone CSS layer has no component API — its surface is the classes above. (Svelte bindings are planned.)
Props
| Prop | Type | Default | Description |
|---|---|---|---|
color | ThemeColor | — | Tints the initials backdrop: primary · secondary · success · warn · danger · info · surface · background. |
inline | boolean | false | Renders as inline-flex with a small margin for flowing inside text. |
radius | RadiusSize | 'rounded' | Corner radius (zero · xs · sm · md · lg · xl · rounded). |
reverse | boolean | false | Reverses the flex direction so the text column appears before the image. |
size | ActionSize | 'lg' | Box size and initials scale (xs · sm · md · lg · xl · xxl). |
spaced | boolean | false | Adds padding around the avatar via ori-size-action-space. |
subtitle | string | — | Secondary line in the text column; rendered whenever title or subtitle is set. |
text | string | — | Drives the initials (up to two letters from the first two words) and the image alt. |
title | string | — | Primary line in the text column; the text column appears when either title or subtitle is set. |
Events & attributes
OriAvatar declares no custom events. It sets inheritAttrs: false and applies v-bind="$attrs"
directly to the <img> element — so src, alt, width, height, loading, decoding, and
any other image attribute or listener fall through to the image, not the wrapper <div>. Native
event listeners (@error, @load, …) follow the same path.
The alt attribute is overridden internally to the value of text (or '' when text is not set)
so there is a single source of truth for the accessible name.
Slots
Each slot overrides the content it names; leave it out and the component falls back to the derived
value or prop. The image itself is not slotted — it comes through $attrs (see above).
| Slot | Falls back to | Description |
|---|---|---|
fallback | the initials derived from text | Imageless fallback content — e.g. a person icon or monogram — shown when there is no image or while it loads. |
title | title prop | Primary line in the text column. |
subtitle | subtitle prop | Secondary line in the text column. |
The text column appears when any of title / subtitle (prop or slot) is set. The #fallback
slot fills the aria-hidden backdrop, so keep its content decorative — the accessible name still
comes from the image alt.
