Skip to main content
xriptxr

Avatar

Info:Media
86

An identity chip: a photo when one loads, a tinted initials-or-icon fallback when it doesn't.

profile picture user photo identity initials gravatar

Live demo

live · @xtyle/astro

Avatar

Initials derived from the name

Pass userName and the initials fall out of it — no image, nothing slotted, nothing hand-typed. Two words give first + last; one word gives one letter.

AL GH KJ RP BL MH P

What fills the chip

An image wins when it loads. Otherwise slotted content wins over the derived initials, so userName is the floor, not a ceiling.

AL

userName

🚀

slot overrides

icon slot

GH

+ presence

Every tone

Accents

AC AC AC AC NE

Statuses

SU IN WA DA

Named hues

RE OR YE GR BL PU BR PI CY GR WH BL

Sizes, circle and square

AL AL AL AL
GH GH GH GH

Presence status

TM

success

TM

warn

TM

danger

TM

neutral

Live presence

GH

pulse

AL

pulse="fast"

KJ

static

Diamonds, frames, and effects

An avatar is any framed chip, not only a face. shape="diamond" turns it 45°, frame rings it in a tone or a gradient, bevel raises that ring, and data-fx adds motion that stays inside the shape.

gradient + bevel + glint

solid + bevel + holo

both effects

solid, no bevel

bevel only

AL AL AL AL GH RP KJ

Stacked group

Each face derives its own initials; AvatarGroup overlaps them and caps the row with a +5 chip.

AL GH KJ RP +5

Avatar presents a person or entity as a compact square or circle. Given a src, it shows the image, cover-cropped to fill; if the image is absent or fails to load, it falls back to initials derived from userName ("Ada Lovelace" → AL) on a soft, hue-tinted background.

Slot your own content to override those initials, or use the icon slot for a glyph instead. The prop is userName, not name, because name carries form-participation meaning on an element and an avatar is not a form control. The fallback tint follows tone, which accepts any of the six semantic roles or the twelve named hues, so a deterministic per-user color is a one-attribute choice. Four sizes (sm, md, lg, xl), three shapes (circle, square, and a diamond that clips the content, the frame, and any effect painted on the host), and an optional corner status dot in any semantic tone round out the surface. frame rings the content in a solid tone or a gradient between two, bevel shades that ring as a raised edge, and the --xtyle-avatar-frame (any color or gradient) and --xtyle-avatar-frame-width custom properties override both. Anything more particular, such as rank pips, a count, or a corner mark, belongs to a mod: the fill renders an empty marks part over the chip and receives the host's own data-* attributes as bindings.hostData, so data-rank="3" is all a mod needs. alt names the image; userName names the avatar when there is no image, so it is announced either way.

When to use

How this component composes with the rest of the set.

Stack a row of avatars into an avatar group; negative inline margin overlaps them.
Pair with Badge for a labeled identity row, or with the status dot for presence.
Feed tone a hash of the user id to get a stable, distinct fallback color per person.
An avatar is any framed, proportional chip, not only a person: a diamond with an icon, a frame, and data-fx="holo" is an inventory gem.
Put data-fx on the avatar for motion: glare?repeat:infinite,rest:3,width:6% is a thin glint that passes now and then, holo a slow iridescent foil, and the two stack.

Props

13 props, straight from the manifest.

PropTypeDefaultBindingsDescription
src string —
html svelte astro
The image URL. When absent or failed, the fallback content shows instead.
alt string —
html svelte astro
Accessible name for the image. Required when src is set; also labels the fallback.
userName html: user-name string —
html svelte astro
The person the avatar stands for. Derives the fallback initials shown when there is no image and nothing slotted ("Ada Lovelace" → AL, "Prince" → P), and names the avatar when no alt is given. Named userName rather than name because name is a form-participation attribute on an element. Attribute: user-name.
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
neutral
html svelte astro
Soft-tint color for the fallback background: any semantic role, accent variant, or named hue.
size AvatarSize
sm md lg xl
md
html svelte astro
Chip size.
shape AvatarShape
circle square diamond
circle
html svelte astro
Outline shape: a circle, a rounded square, or a diamond (a square turned 45°, content kept upright). A diamond clips the overlays an effect paints on the host, so glare or holo stays inside the shape, while the marks layer and the status dot are free to sit over its corners.
frame AvatarFrame
none solid gradient
none
html svelte astro
A ring around the content: solid paints it in frameTone (the line color by default), gradient runs from frameTone to frameTone2 (the accent pair by default). The --xtyle-avatar-frame custom property takes any color or gradient instead, and --xtyle-avatar-frame-width sets the thickness.
frameTone html: frame-tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
—
html svelte astro
The frame's color, or the gradient's first stop. Attribute: frame-tone.
frameTone2 html: frame-tone-2 FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
—
html svelte astro
The gradient frame's second stop. Attribute: frame-tone-2.
bevel boolean false
html svelte astro
Shades the frame as a raised edge lit from the top left, from the theme's own --white and --black. Implies a solid frame when frame is not set.
status Tone
accent neutral danger success warn info
—
html svelte astro
When set, shows a corner status dot in this semantic tone.
statusLabel html: status-label string —
html svelte astro
Accessible name for the status dot (e.g. "Online"); announced as additional avatar text.
pulse boolean | "slow" | "fast" —
html svelte astro
Breathe the status dot for a live / online presence: a bare true pulses slow, "fast" quick. A no-op without status, and held still under prefers-reduced-motion.

Appearance

Variants

circle

.xtyle-avatar

Fully rounded, the default identity shape.

square

.xtyle-avatar--square

A rounded square, for entities and projects rather than people.

diamond

.xtyle-avatar--diamond

A square turned 45° with the content kept upright, for items, charms, and gems rather than people.

Sizes

sm

.xtyle-avatar--sm

Compact, for dense lists.

md

default
.xtyle-avatar

Default.

lg

.xtyle-avatar--lg

Large, for headers.

xl

.xtyle-avatar--xl

Extra large, for profile hero.

States

fallback

.xtyle-avatar__fallback

No image: the tinted initials-or-icon stand-in fills the chip.

status

.xtyle-avatar__status-dot

A corner dot conveys presence; its color is the chosen status tone, ringed in the surface.

pulse

.xtyle-avatar--pulse-slow .xtyle-avatar__status-dot

With pulse, the status dot breathes on a soft opacity loop so the avatar reads as live, at a slow or fast cadence; held still under reduced-motion.

framed

.xtyle-avatar--frame-solid, .xtyle-avatar--frame-gradient

With frame, the content sits inside a ring painted in a tone, a gradient, or whatever --xtyle-avatar-frame holds.

bevel

.xtyle-avatar--bevel

With bevel, the frame catches a highlight on its top-left edge and a shade on its bottom-right.

Anatomy

The named parts that make up the component. Created from script it renders a shadow root, where a ::part() handle is reachable from your own stylesheet and the class beside it is internal. Upgraded over server-rendered markup it renders light DOM, where the class is the handle.

avatar

Success:::part(avatar) .xtyle-avatar

The root chip carrying the size, shape, and tone classes; sizes the image and fallback and anchors the status dot.

--space-7 --font-sans --text-sm --weight-semibold --leading-tight --neutral-text --radius-full

image

Success:::part(image) .xtyle-avatar__image

The portrait image, cover-cropped to fill the chip and clipped to the chip's shape.

fallback

Success:::part(fallback) .xtyle-avatar__fallback

The initials-or-icon stand-in shown when no image is present, painted with the tone's soft tint inside a hairline edge that clears 3:1 against the page.

--neutral-bg --neutral-text --line-strong --border-thin

status-dot

Success:::part(status-dot) .xtyle-avatar__status-dot

The optional corner indicator, ringed in the surface color so it reads against any background.

--space-2 --neutral --radius-full --border-thick --bg-1

marks

Success:::part(marks) .xtyle-avatar__marks

An empty layer over the whole chip, rendered for mods: a fill that paints pips, a count, or a corner badge targets it, and bindings.hostData carries the host's data-* attributes to draw from. Hidden while empty.

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 86/86 consumed tokens produced default register: 311 tokens

Live coverage check against the xtyle-default register (derive(xtyleDefault, { anchors }) → coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--accent --accent-2 --accent-2-bg --accent-2-text --accent-3 --accent-3-bg --accent-3-text --accent-4 --accent-4-bg --accent-4-text --accent-bg --accent-text --bg-1 --black --black --black-bg --black-text --blue --blue-bg --blue-text --border-thick --border-thin --brown --brown-bg --brown-text --cyan --cyan-bg --cyan-text --danger --danger-bg --danger-text --font-sans --gray --gray-bg --gray-text --green --green-bg --green-text --info --info-bg --info-text --leading-tight --line-2 --line-strong --neutral --neutral-bg --neutral-text --orange --orange-bg --orange-text --pink --pink-bg --pink-text --purple --purple-bg --purple-text --radius-full --radius-lg --radius-md --radius-sm --red --red-bg --red-text --space-2 --space-4 --space-6 --space-7 --space-8 --success --success-bg --success-text --text-body --text-lg --text-sm --text-xs --warn --warn-bg --warn-text --weight-semibold --white --white --white-bg --white-text --yellow --yellow-bg --yellow-text

Slots

default
html svelte astro

Custom fallback content shown when no image loads. Overrides the initials userName derives — leave it empty and those initials are what you get.

icon
html svelte astro

An icon fallback, used in place of initials when no image loads.

Accessibility

The image carries alt; the binding warns at runtime when src is set without it.
userName names the avatar when there is no alt, so an image-less avatar is announced by the person it stands for rather than by two bare initials.
When the image is absent or errors, the fallback initials or aria-label'd icon remain in the accessibility tree so the avatar is still announced.
The decorative status dot is aria-hidden; its meaning rides on statusLabel as visually-hidden text in the accessibility tree.
pulse is decorative motion only, never the carrier of meaning: put the live state in statusLabel ("Online") so it reads the same to assistive tech and under prefers-reduced-motion, where the pulse holds still.
The fallback icon slot is decorative. Provide alt (or fallback initials) so the avatar still has a name.
A frame, a bevel, and a diamond are decoration only. Anything a mod paints into marks (a rank, a count) belongs in alt as well, so it is announced and not only seen.

Code

Image, fallback, and status

A photo when one loads, tinted initials or an icon when it doesn't, with an optional presence dot.

<!-- a photo when one loads -->
<xtyle-avatar user-name="Ada Lovelace" alt="Ada Lovelace" src="/avatars/ada.jpg"></xtyle-avatar>

<!-- no image: the initials fall out of the name ("Grace Hopper" → GH) -->
<xtyle-avatar user-name="Grace Hopper" tone="info" size="lg"></xtyle-avatar>

<xtyle-avatar user-name="Katherine Johnson" tone="purple" shape="square" status="success" status-label="Online"></xtyle-avatar>

<!-- slot your own content to override the derived initials -->
<xtyle-avatar user-name="Project Apollo" tone="warn">🚀</xtyle-avatar>

<xtyle-avatar alt="Unknown user" size="xl">
	<svg slot="icon" viewBox="0 0 24 24" aria-hidden="true">
		<path fill="currentColor" d="M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm0 2c-5 0-9 2.5-9 6v2h18v-2c0-3.5-4-6-9-6Z" />
	</svg>
</xtyle-avatar>

Live presence

A pulsing status dot reads as online in real time; statusLabel carries the meaning for assistive tech.

<xtyle-avatar user-name="Grace Hopper" status="success" status-label="Online" pulse></xtyle-avatar>

Diamonds, frames, and effects

A diamond with a gradient, bevelled frame and a repeating thin glint; a holo foil on a solid frame; a framed square.

<xtyle-avatar shape="diamond" frame="gradient" frame-tone="yellow" frame-tone-2="orange" bevel tone="purple" alt="Ring of embers" data-fx="glare?repeat:infinite,rest:3,width:6%" style="--fx-glare-repeat:infinite;--fx-glare-rest:3;--fx-glare-width:6%">
	<xtyle-icon slot="icon" name="ember--flame" aria-hidden="true"></xtyle-icon>
</xtyle-avatar>
<xtyle-avatar shape="diamond" frame="solid" frame-tone="gray" bevel tone="cyan" alt="Tide charm" data-fx="holo">
	<xtyle-icon slot="icon" name="tide--drop" aria-hidden="true"></xtyle-icon>
</xtyle-avatar>
<xtyle-avatar shape="square" frame="solid" frame-tone="accent" user-name="Ada Lovelace"></xtyle-avatar>

Data for a mod's marks

The host's data-* attributes reach every fill as bindings.hostData, and the empty marks part is where a mod paints from them.

<!-- a mod's avatar fill reads bindings.hostData.rank and paints pips into the empty marks part -->
<xtyle-avatar shape="diamond" frame="solid" tone="green" alt="Oak ring, rank 3 of 5" data-rank="3" data-rank-max="5">
	<xtyle-icon slot="icon" name="oak--leaf" aria-hidden="true"></xtyle-icon>
</xtyle-avatar>