Avatar
Display an image or initials representing a user.
use herogpui::components::avatar::Avatar;Avatar on docs.rsSource at v0.14.0
Usage
Showing Usage, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
Fallback text uses 14px/20px, 12px/16px for small and 16px/24px for large avatars. Here `radius` sets 8px corners and `sx` squares just the top-left corner on the fallback and loaded image. An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::Avatar;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![Avatar::new("avatar-avatar")
.name("Jane Doe")
.radius(px(8.))
.sx(|el| el.rounded_tl(px(0.)))
.into_any_element()])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Avatar, AvatarVariant, Color, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
Avatar::new("avatar-avatar").name("Jane Doe")
.into_any_element(),
Avatar::new("avatar-avatar")
.into_any_element(),
// v3's own Fallback Content example drives a
// deliberately broken URL with
// `<Avatar.Fallback delayMs={600}>`; an unregistered
// asset path fails identically here (no network), and
// the initials replace the box once the delay elapses.
spec(
"Broken image",
Avatar::new("avatar-avatar")
.name("NA")
.src("images/avatar-broken.png")
.delay_ms(600),
cx,
),
Avatar::new("avatar-avatar")
.name("HG")
.fallback(gpui::svg()
.size(px(16.))
.path(icons::HEART_FILL)
.text_color(cx.colors().foreground)
.into_any_element())
.into_any_element(),
Avatar::new("avatar-color-avatar")
.name("HG")
.color(Color::Accent)
.variant(AvatarVariant::Soft)
.fallback_color(Color::Warning)
.into_any_element(),
])Also calls spec (included when you copy).
An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Avatar, Size};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(Size::ALL
.iter()
.enumerate()
.map(|(i, s)| {
Avatar::new(("size-avatar", i))
.name("Ada Lovelace")
.size(*s)
.into_any_element()
}))An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Avatar, Color};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(Color::ALL
.iter()
.enumerate()
.map(|(i, c)| Avatar::new(("color-avatar", i)).name("HG").color(*c)))An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Avatar, AvatarVariant, Color};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(AvatarVariant::ALL
.iter()
.enumerate()
.map(|(i, v)| {
Avatar::new(("variant-avatar", i))
.name("HG")
.color(Color::Accent)
.variant(*v)
.into_any_element()
}))A custom image source composes the same way: the loader below supplies the embedded sample image itself, and `on_load` fires once the image is ready and replaces the fallback. An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Avatar, Toast};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
use std::sync::Arc;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Avatar::new("avatar-loader-avatar")
.name("JD")
.src(sample_avatar_source())
.fallback("JD")
.on_load(|_, cx| {
Toast::new("Avatar image loaded")
.description("on_load fired once for the custom source.")
.push(Some(std::time::Duration::from_secs(3)), cx);
})
.into_any_element(),
])Also calls sample_avatar_source (included when you copy).
Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
/// A labelled specimen — the caption HeroUI puts under each variant.
fn spec(label: &str, el: impl IntoElement, cx: &gpui::App) -> AnyElement {
let muted = cx.colors().muted;
gpui::div()
.flex()
.flex_col()
.items_center()
.gap(px(6.))
.child(el)
.child(
gpui::div()
.text_size(px(11.))
.text_color(muted)
.child(label.to_owned()),
)
.into_any_element()
}/// One stable custom image source for the Avatar "Custom Image Component"
/// demo: the loader `Arc` is built once, so the avatar's per-source keyed
/// state and its `on_load` keep their identity across frames.
fn sample_avatar_source() -> gpui::ImageSource {
type AvatarLoader = std::sync::Arc<
dyn Fn(
&mut gpui::Window,
&mut gpui::App,
)
-> Option<Result<std::sync::Arc<gpui::RenderImage>, gpui::ImageCacheError>>
+ Send
+ Sync,
>;
static LOADER: std::sync::OnceLock<AvatarLoader> = std::sync::OnceLock::new();
let loader: &AvatarLoader = LOADER.get_or_init(|| {
let image = std::sync::Arc::new(gpui::Image::from_bytes(
gpui::ImageFormat::Png,
include_bytes!("../../../assets/herogpui/sample.png").to_vec(),
));
std::sync::Arc::new(move |window: &mut gpui::Window, cx: &mut gpui::App| {
image.clone().use_render_image(window, cx).map(Ok)
})
});
gpui::ImageSource::Custom(loader.clone())
}Anatomy
Rust types
Avatar is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Avatar looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
size(Size) | Size::Sm | Size::Md | Size::Lg | Avatar size: 32/40/48px edge, with `sm` rounding one step tighter and stepping the fallback text down to 12px, and `lg` stepping it up to 16px. Inside an `AvatarGroup`, an omitted size comes from the group. |
color(Color) | Color::Default | Color::Accent | Color::Success | Color::Warning | Color::Danger | Fallback color theme. The base avatar fills `bg-default` for every color — the color recolours the initials via the soft-foreground token. |
variant(AvatarVariant) | AvatarVariant::Default | AvatarVariant::Soft | Visual style variant. `soft` clears the base fill and paints `bg-{role}-soft` with the same soft foreground. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 8 entries ported, 3 partial, 9 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
size( | Size:: | Size:: | Avatar size: 32/40/48px edge, with `sm` rounding one step tighter and stepping the fallback text down to 12px, and `lg` stepping it up to 16px. Inside an `AvatarGroup`, an omitted size comes from the group. |
color( | Color:: | Color:: | Fallback color theme. The base avatar fills `bg-default` for every color — the color recolours the initials via the soft-foreground token. |
variant( | AvatarVariant:: | AvatarVariant:: | Visual style variant. `soft` clears the base fill and paints `bg-{role}-soft` with the same soft foreground. |
src( | string | — | Image source URL. A plain string or path loads through gpui's asset system (a parseable URI is fetched, anything else is an embedded resource); the gpui `ImageSource::Image` / `Render` / `Custom` variants are the explicit parts for images the app already holds or loads itself. |
on_load(Partial | Fn( | — | Callback when the image loads successfully and replaces the fallback. Fires once per source, on the first observed success, outside the layout phase; there is no event payload to hand over. |
on_error(Partial | Fn( | — | Callback when there's an error loading the image; the fallback initials replace the image on that same failure. A decoded image with zero width counts as a failure (Radix Avatar 1.2.6 `naturalWidth > 0`). Fires once per source; no event payload. |
delay_ms( | number | — | Delay before showing the fallback, measured from mount so a slow load does not flash the initials behind it. A success inside the window renders before it elapses; a failure inside it waits for the same window rather than restarting it. |
fallback_color( | Color:: | — | Override color from parent. Its own documented prop, not an alias: it overrides the parent `color` for everything the fallback paints, while the parent color still governs the rest. |
Not ported9 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
Avatar.className | |
Avatar.Image.srcSet | The image `srcset` attribute for responsive images. Browser-only: gpui's asset system resolves one resource per source and never selects between candidates. |
Avatar.Image.sizes | The image `sizes` attribute. Browser-only hint for `srcset` selection; there is no viewport-density image pick to hint. |
Avatar.Image.alt | Alternative text for the image. Gpui-pre 0.3.3 has no accessibility tree to carry it. |
Avatar.Image.asChild | Merges props onto a child element instead of rendering a native `img`. There is no element graph to merge onto; a gpui `ImageSource::Custom` loader is the equivalent seam for a custom image component. |
Avatar.Image.crossOrigin | CORS setting for the image request. Browser fetch metadata with no analogue in gpui's asset system. |
Avatar.Image.loading | Native lazy loading attribute. Gpui loads a source when it is first observed; there is no viewport-distance scheduler to defer with. |
Avatar.Image.className | |
Avatar.Fallback.className |
Parts
| Part | Description |
|---|---|
Avatar | Root container on the `.avatar` BEM class: `relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-3xl bg-default`. The name initials come from the port's own `name` builder (has no `name` prop); the load progress and the `delayMs` window key on the image source. |
AvatarPartial | `absolute inset-0 aspect-square size-full` image with an opacity transition. Draws the loaded image directly inside the root (`img(data).size_full().rounded(radius)`), applying the root radius to keep the image inside the Avatar boundary, and does not animate the swap. |
Avatar | `flex size-full items-center justify-center bg-default text-sm font-medium` fallback box. The separate fallback container centers initials or custom `fallback` children with 14px/20px medium text (12px/16px for small and 16px/24px for large avatars), painted `text-{role}-soft-foreground`. |