Skip to content

PlAvatar

A picture of a person or a thing, at a known size, that is never an empty box. When there is no picture there are initials; when there are no initials there is a silhouette.

React
tsx
import { PlAvatar } from 'plass-ui';

<PlAvatar name="Nadia Rowan" src="/nadia-rowan.webp" />;
<PlAvatar name="Nadia Rowan" />;
dart
import 'package:plass_ui/plass_ui.dart';

const PlAvatar(name: 'Nadia Rowan', image: NetworkImage('/nadia-rowan.webp'));
const PlAvatar(name: 'Nadia Rowan');

Props

PropTypeDefaultDescription
variantshared'solid' | 'glass' | 'ghost''ghost'What the sheet behind the fallback is made of — invisible once a picture has loaded, apart from the edge it keeps. ghost by default, because a page of saturated circles is a page nobody can read a name off
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The box the picture is drawn in — the control heights, so an avatar and the button beside it in a toolbar are the same height
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. An avatar is the thing being coloured, so its sheet takes the tint
elevationshared0 | 1 | 2 | 30Drop shadow depth. An avatar is a picture set into the page rather than a key resting on it
srcstringThe picture. Until it loads, and forever if it fails, the fallback is what is drawn
srcSetstringCandidate images at other resolutions, as on any img
altstringWhat the picture says. Defaults to name, and to an empty string when there is no name
namestringWho or what this is. It names the picture, the initials are derived from it, and it is what a screen reader hears instead of them
initialsstringThe initials, written out, for when the derivation rule got them wrong
shape'circle' | 'square''circle'The crop. circle for a portrait, square for the library’s own fillet — for a logo or an icon drawn to the edges of a rectangle
delaynumberHow long to wait before drawing the fallback, in milliseconds. Set it to about the time a cached image takes and the initials stop flashing
imagePropsOmit<ComponentPropsWithoutRef<'img'>, 'src' | 'srcSet' | 'alt'>Anything else the img needs — loading, crossOrigin, referrerPolicy
onLoadingStatusChange(status: 'idle' | 'loading' | 'loaded' | 'error') => voidCalled as the picture moves between the four loading states
childrenReactNodeThe fallback, drawn instead of the initials — an icon, a logo, a single emoji
PropTypeDefaultDescription
variantsharedPlassVariant?PlassVariant.ghostWhat the sheet behind the fallback is made of — invisible once a picture has loaded, apart from the edge it keeps. ghost by default, because a page of saturated circles is a page nobody can read a name off
sizesharedPlassSize?PlassSize.mdThe box the picture is drawn in — the control heights, so an avatar and the button beside it in a toolbar are the same height
colorsharedPlassColor?PlassColor.primarySemantic colour role. An avatar is the thing being coloured, so its sheet takes the tint
elevationsharedint?0Drop shadow depth. An avatar is a picture set into the page rather than a key resting on it
imageImageProvider?The picture, as an ImageProvider rather than a URL — a NetworkImage, an AssetImage or a provider from a caching package all fit. Until it loads, and forever if it fails, the fallback is what is drawn
nameString?Who or what this is. It names the picture, the initials are derived from it, and it is what a screen reader hears instead of them
initialsString?The initials, written out, for when the derivation rule got them wrong
semanticLabelString?What the picture says. Defaults to name, and to an empty string when there is no name
shapePlAvatarShape?PlAvatarShape.circleThe crop. circle for a portrait, square for the library’s own fillet — for a logo or an icon drawn to the edges of a rectangle
childWidget?The fallback, drawn instead of the initials — an icon, a logo, a single emoji

Every native <span> attribute passes straight through. color is excluded from the pass-through because it is a Plass prop here.

image is an ImageProvider rather than a URL, which is the shape every image in Flutter has: a NetworkImage, an AssetImage, a MemoryImage or a provider from a caching package all fit without the component having to know which.

There is no density: an avatar has no padding to tighten. It carries no status dot of its own either. An avatar with a green mark on it is a PlBadge with an avatar in it.

What the shared axes (variant size color elevation) mean across the library is in prop conventions.

Examples

The fallback

Three things can be drawn and exactly one of them is at a time: the picture, if src is given and it loads; otherwise whatever stands in for it, children, or initials, or the initials derived from name; and failing all of those, a silhouette.

Which one is showing is Base UI's Avatar to decide, because "has the image loaded" is a question with four answers and a race in the middle of it.

Which one is showing is decided by the Image itself: its frameBuilder shows the fallback until the first frame arrives, and its errorBuilder shows it for good if none ever does. There is no loading enum, because a picture that has not arrived and a picture that never will are the same case for as long as they last.

There is no delay. It exists in the React build so the initials do not flash up in front of a cached image; here a picture already in the image cache is decoded synchronously and the fallback is never built at all.

The derivation is the first character of the first word plus the first character of the last. "Jane Doe" is JD. A single-token name gives one character, because two characters of a Korean, Japanese or Chinese name at 40px is a smudge where one is a name.

React

variant

An avatar is the thing being coloured, a portrait of one particular person, so its sheet takes the tint, as a PlAlert's does and unlike a PlCard's. The edge is the neutral hairline rather than the sheet's own white one: an avatar is very often laid on something opaque, where white light on a cut edge is a claim about a page wash that is not behind it.

ghost is the default rather than solid, which is the other way round from a PlButton. A directory is a page of avatars, and a page of saturated circles is a page nobody can read a name off.

React

shape

circle is the default, because that is what a portrait has been for as long as there have been portraits. square takes the library's own fillet instead, which is what a logo or a repository icon wants. Those are drawn to the edges of a rectangle and a round crop eats them.

React

size

The control heights, so an avatar and the button beside it in a toolbar sit on the same baseline.

React

color

React

A stack of them

A stack of overlapping faces with a +n on the end is a PlStack with avatars in it. It is a general pile rather than an avatar component, so it sets no axes on what it holds. Put a PlassProvider around it for size and color, and write the rest on the avatars.

Accessibility

  • The picture takes alt, falling back to name, falling back to an empty alt. Empty rather than absent: an avatar beside the person's own name in a row is decoration, and alt left off is what makes a screen reader read the file name out instead.
  • JD read out loud is two letters, not a person. When there is a name it becomes the fallback's accessible name and the initials are hidden as the picture they are standing in for.
  • A silhouette says nothing at all. There is no name to announce, and "graphic" is not information.
  • An avatar that is also a link or a button has to be one: put it inside a real <a> or <button> and give that element the name.
  • The avatar takes semanticLabel, falling back to name, falling back to nothing at all. Nothing rather than a guess: an avatar beside the person's own name in a row is decoration, and saying the name twice is worse than saying it once.
  • JD read out loud is two letters, not a person. When there is a name it becomes the accessible name and the initials are excluded as the picture they are standing in for. With no name the initials are all there is, and they are read.
  • A silhouette says nothing at all. There is no name to announce, and "graphic" is not information.
  • An avatar that is also a link or a button belongs inside one: a PlButton or a PlCard with onPressed, named there.

Differences from the React build

ReactFlutterWhy
src / srcSet / imagePropsimageAn ImageProvider is the shape every image in Flutter has, and it already covers resolution variants, headers and caching.
altsemanticLabelFlutter's name. It names the avatar rather than an inner element, because there is no inner element to name.
delayA cached image decodes synchronously here, so the fallback never flashes and there is nothing to wait out.
onLoadingStatusChangeThere is no four-state machine to report: the fallback is shown until a frame arrives and for good if none does. An ImageProvider's own ImageStream is where a caller who needs the states goes.
childrenchildFlutter's name.
className, styleThere is no class list and no style attribute to pass through.

Released under the MIT License