Avatar
Overview
The Avatar component represents a person or entity as a compact image.
It falls back
automatically from a photo (src) to initials (from name/initials) to a custom icon, and
finally to a generic default icon — so you never have to hand-roll the broken-image or
missing-photo case.
Import
import { Avatar } from '@allxsmith/bestax-bulma';
Usage
Photo with Automatic Fallback
A working photo renders as an image; if the src fails to load, Avatar swaps to initials
derived from name automatically — no broken-image icon.
<Avatars spaced> <Avatar src="https://github.com/allxsmith.png" name="Al Smith" size="64x64" /> <Avatar src="https://example.invalid/missing.jpg" name="Grace Hopper" size="64x64" /> </Avatars>
Initials
With no src, initials render on a deterministic auto background color derived from name.
<Avatars spaced> <Avatar name="Ada Lovelace" /> <Avatar name="Grace Hopper" /> <Avatar name="Katherine Johnson" /> </Avatars>
Icon Fallback
Pass an icon to control the final fallback when there is no photo, name, or initials.
<Avatar icon={<Icon name="user" />} color="info" shape="rounded" />
Shapes
The shape prop switches between a circle, a rounded square, and a plain square.
<Avatars spaced> <Avatar name="Circle" shape="circle" /> <Avatar name="Rounded" shape="rounded" /> <Avatar name="Square" shape="square" /> </Avatars>
Sizes
Preset sizes mirror Image's fixed-size list; a number renders a pixel size.
<Avatars spaced> <Avatar name="Ada Lovelace" size="24x24" /> <Avatar name="Ada Lovelace" size="32x32" /> <Avatar name="Ada Lovelace" size="48x48" /> <Avatar name="Ada Lovelace" size="64x64" /> <Avatar name="Ada Lovelace" size={20} /> </Avatars>
Clickable Avatar
Set href to render the avatar as a link (or pass as for a custom element).
<Avatar name="Ada Lovelace" href="https://bestax.io" />
href and target only reach a target that can be a link: an <a>, a custom element, or a
component passed to as, such as your router's link. On a plain element like as="figure" or
as="div" the avatar renders without them, because HTML gives those elements neither, and a
development build logs a console warning naming the ones it dropped. Use as="a" or a link
component when you want the link. An empty href asks for no link: with no as it renders a
<figure>, and it draws no warning.
Forwarding Props to the Image
imageProps is spread onto the underlying <img> — handy for native attributes like
loading, crossOrigin, or referrerPolicy. A custom onError is chained before the
automatic initials/icon fallback runs.
<Avatar src="https://github.com/allxsmith.png" name="Al Smith" size="64x64" imageProps={{ loading: 'lazy' }} />
Forwarded ref
Avatar forwards a ref to its root element — the <figure>, or the <a> that an href selects — not to the inner <img>.
function example() { const avatarRef = React.useRef(null); const [tag, setTag] = React.useState(null); return ( <> <Avatar ref={avatarRef} name="Ada Lovelace" size="64x64" /> <Button mt="3" onClick={() => setTag(avatarRef.current?.tagName)}> Read the tag from its ref </Button> <p>Rendered element: {tag ?? '—'}</p> </> ); }
Accessibility
- Image avatars use
alt(falling back toname) for their accessible name. - Initials/icon avatars expose
role="img"andaria-label(fromalt/name) — unless rendered as a link or button, where the native link/button role andaria-labelare used instead. A custom component passed toascounts as interactive, since a router link takestorather than this component'shref. If yours renders something that really is just a picture, say so withrole="img"and it's treated as one —alt=""included. A truthyaria-hiddensays it too, and so dorole="presentation"androle="none", though ARIA's own conflict resolution drops those two whenever the avatar still carries a name — preferrole="img". A role claiming the opposite, such as"button", doesn't, and neither does anhref. - Decorative avatars: pass an explicit
alt=""when the avatar repeats information already visible next to it (e.g. beside the author's name in a comment row). The image stays decorative and an initials/icon avatar is skipped entirely (aria-hidden), avoiding double-speak. The opt-out never applies to a link/button avatar — an interactive element always keeps an accessible name (fromname, or a generic"Avatar"fallback) — and a custom component passed toascounts as one until it says otherwise, soalt=""on a custom wrapper needs that signal next to it. - A link/button avatar with no
alt/name(e.g. an API that returns only a photo URL) still gets anaria-labelfallback rather than rendering a nameless control. as="button"defaults totype="button", so a clickable avatar inside a form doesn't submit it.- The default fallback icon is
aria-hidden.
Related Components
Avatars: An overlapping group ofAvatars with a "+N" surplus bubble.Badge: A status/count indicator that overlays anAvatar(or any element).Image: Bulma's fixed-ratio image container.- Helper Props: Bulma helper props for spacing, color, etc.
Additional Resources
Props
| Prop | Type | Default | Description |
|---|---|---|---|
as | React.ElementType | — | Element/component to render as. Defaults to 'a' when href is set, else 'figure'. This also decides whether the avatar is treated as interactive, which is what keeps role="img" and the alt="" decorative opt-out off a link or button. A custom component counts — a router link takes to rather than this component's href, so its own props cannot say — while 'a', 'button', and a custom element given an href count for the reason they read. If your custom component renders something that really is just a picture, say so with role="img" and it is treated as one, alt="" included. A truthy aria-hidden says it too, and so do role="presentation" and role="none" — though ARIA's own conflict resolution drops those two whenever the avatar still carries a name, so prefer role="img". A role claiming the opposite, such as "button", says nothing here, and neither does an href: that settles it on its own. A genuine 'a'/'button'/href avatar keeps its accessible name either way. 'button' renders type="button" unless you pass type="submit" or type="reset", so an avatar inside a form does not submit it. |
className | string | — | Additional CSS classes to apply. |
src | string | — | Image URL. On load error (or if absent), falls back to initials, then icon. |
alt | string | — | Alternate text for the image (used for the accessible name in every render mode). An explicit alt="" marks a non-interactive avatar as decorative. A link or button avatar is never decorative — it keeps an accessible name — and a custom component passed to as counts as one unless it states otherwise, so alt="" on a custom wrapper needs that signal alongside it. as documents which props carry it. |
name | string | — | Derives initials and a deterministic background color when no src is shown. |
initials | string | — | Explicit initials override (else derived from name). |
icon | React.ReactNode | — | Final fallback, rendered when there is no src, name, or initials. |
size | '16x16' | '24x24' | '32x32' | '48x48' | '64x64' | '96x96' | '128x128' | number | — | Preset size, or a pixel size when a number. |
shape | 'circle' | 'rounded' | 'square' | 'circle' | Avatar shape. Default 'circle'. |
color | AvatarColor | — | Background color for initials/icon avatars (else auto-derived from name). |
href | string | — | When set, renders the avatar as a link: an <a> unless as names the element itself. An as target declaring its own href supersedes this one, and its type and its requiredness are what apply. It is passed on only to a target that can be a link: an a, a custom element, or a component. Any other as you pass, such as 'figure' or 'div', still accepts it but renders without it, because an href is not valid HTML on those elements, and a development build logs a console warning naming what was dropped. To make such an avatar a link, render it as="a" or pass a link component to as. An empty href asks for no link: with no as it renders a <figure>, and it draws no warning. |
target | string | — | Anchor target, passed on only where href is (an a, a custom element, or a component) and superseded by the target's own declaration the way href is. Any other as you pass renders without it, with the same development warning as href, except 'form': it declares its own target, so there the attribute is still withheld but draws no warning. |
rel | string | — | Anchor rel, passed on only where href is (an a, a custom element, or a component) and superseded by the target's own declaration the way href is. |
imageProps | React.ImgHTMLAttributes<HTMLImageElement> | — | Extra props forwarded to the underlying <img> (e.g. loading, crossOrigin); its onError is chained before the fallback fires. |
style | React.CSSProperties | — | Inline styles, merged after the size style. |
ref | PolymorphicRef<React.ElementType> | — | Ref forwarded to the element as renders, typed from as: the DOM node for an intrinsic tag, or whatever handle a custom component exposes. |
... | Remaining props of the element or component selected by as (default <figure>) and Bulma helper props | — | See Helper Props |
Types:
AvatarColor:'primary'|'link'|'info'|'success'|'warning'|'danger'|'black'|'dark'|'light'|'white'— Valid color values for the Avatar component.
CSS & Sass Variables
Avatar registers these variables on its own .avatar element. Override them there (or via className) — a value set on an ancestor is only inherited, and loses to the component-level declaration. See Theme.
| CSS Variable | Sass Variable | Default |
|---|---|---|
--bulma-avatar-size | $avatar-size | 48px |
--bulma-avatar-background | $avatar-background | var(--bulma-background) |
--bulma-avatar-color | $avatar-color | var(--bulma-text) |
--bulma-avatar-weight | $avatar-weight | var(--bulma-weight-semibold) |
--bulma-avatar-rounded-radius | $avatar-rounded-radius | var(--bulma-radius-large) |