Browse docs
Browse docs
Show a user. Fall back gracefully when there's no picture.
import { Avatar } from '@dashforge/tw';
<Avatar src="/avatars/jane.png" alt="Jane Doe" /><Avatar src="/u/jane.png" alt="Jane Doe" /> {/* image */}
<Avatar name="Jane Doe" /> {/* initials: "JD" */}
<Avatar name="Jane Doe" fallbackIcon={<User />} /> {/* custom fallback */}
<Avatar /> {/* generic SVG */}Avatar resolves in this order, falling back on each failure:
src (image) — if it loadsname → auto-generated initials (first letter of the first 2 whitespace-separated words, uppercased)fallbackIcon (custom ReactNode)import { Avatar, Stack } from '@dashforge/tw';
import { Building } from 'lucide-react';
<Stack direction="row" gap={3} wrap align="center">
<Avatar src="/avatars/jane.png" alt="Jane Doe" name="Jane Doe" /> {/* step 1: src loads */}
<Avatar src="/avatars/missing.png" alt="Jane Doe" name="Jane Doe" /> {/* step 2: initials "JD" */}
<Avatar fallbackIcon={<Building size={18} />} /> {/* step 3: custom icon */}
<Avatar /> {/* step 4: generic SVG */}
</Stack><Avatar name="Jane" shape="circle" /> {/* default */}
<Avatar name="Jane" shape="rounded" /> {/* soft corners */}
<Avatar name="Jane" shape="square" /> {/* hard corners */}Override with explicit radius (Box-style token) for custom shapes:
<Avatar name="Jane" shape="rounded" radius="lg" />Five-step scale:
import { Avatar, Stack } from '@dashforge/tw';
<Stack direction="row" gap={3} align="center">
<Avatar name="Jane Doe" size="xs" color="primary" />
<Avatar name="Jane Doe" size="sm" color="primary" />
<Avatar name="Jane Doe" size="md" color="primary" />
<Avatar name="Jane Doe" size="lg" color="primary" />
<Avatar name="Jane Doe" size="xl" color="primary" />
</Stack>For the no-image case (initials/icon), color and tone resolve to the Dashforge token palette — fully type-safe:
<Avatar name="Jane" color="primary" tone={500} />
<Avatar name="Jane" color="success" tone={600} />
<Avatar name="Jane" color="danger" tone={500} />
<Avatar name="Jane" color="neutral" tone={300} />color is constrained to the palette keys (primary, secondary, success, ...). tone is constrained to the scale steps (50, 100, 200, ..., 900). Invalid combinations fail to compile.
For colors outside the palette: fall back to sx / className override (escape hatch).
onError handlerCustom fallback on image load failure:
<Avatar
src="/u/maybe.png"
alt="Maybe Jane"
name="Maybe Jane"
onError={(e) => analytics.track('avatar.load.error', { src: e.currentTarget.src })}
/>The default onError swaps to step 2 (initials) automatically — your handler runs in addition, not instead.
<AvatarGroup> wraps Avatar children, applies the same size to all, and shows a +N indicator when the count exceeds max.
import { Avatar, AvatarGroup } from '@dashforge/tw';
<AvatarGroup max={3}>
<Avatar name="Alice Smith" color="primary" />
<Avatar name="Bob Lee" color="success" />
<Avatar name="Carla Vega" color="warning" />
<Avatar name="David Park" color="info" />
<Avatar name="Erin Kim" color="danger" />
</AvatarGroup>
{/* Renders: A · B · C · +2 */}
<AvatarGroup size="lg" max={4}>
{/* size="lg" propagates to all children via cloneElement */}
<Avatar name="Alice" /> <Avatar name="Bob" /> <Avatar name="Carla" /> <Avatar name="David" />
</AvatarGroup>withRingBy default each avatar in the group gets a ring-neutral-50 ring — a subtle separator. Disable for a flush stack:
<AvatarGroup withRing={false} max={4}>
{/* ... */}
</AvatarGroup>The ring uses ring-neutral-50 (NOT dark:ring-neutral-100) because the neutral palette auto-inverts via the CSS var swap. Same pattern as the rest of the catalog — see Design decisions.
<Avatar name="Jane Doe"
access={{ requires: 'workspace.admin', when: 'denied:hide' }}
/>
<Avatar src="/u/me.png"
visibleWhen={(engine) => engine.getValue('showAuthor') === true}
/><Avatar> props| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image URL. Falls back to initials/icon/SVG on error. |
alt | string | — | Image alt text. Required when src is set (a11y). |
name | string | — | Used for auto-initials when src is missing/errors. First letters of the first 2 whitespace-separated words. |
fallbackIcon | ReactNode | generic SVG | Custom fallback at step 3 of the chain. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Diameter / side length. |
shape | 'circle' | 'rounded' | 'square' | 'circle' | Corner shape. |
radius | 'sm' | 'md' | 'lg' | 'xl' | 'full' | derived | Box-style token override for radius. |
color | palette key | 'neutral' | Token palette key for the no-image background. |
tone | 50 | 100 | 200 | ... | 900 | 200 | Tone within the palette. |
onError | ImgEventHandler | — | Additive handler called when the image fails to load. |
access | AccessSpec | — | RBAC gating. |
visibleWhen | (engine: Engine) => boolean | — | Engine-reactive predicate. |
className | string | — | Merged via tailwind-merge. |
sx | string | — | String-form Tailwind override. |
<AvatarGroup> props| Prop | Type | Default | Description |
|---|---|---|---|
max | number | 5 | Maximum visible avatars before overflow +N indicator. |
size | Avatar['size'] | — | Propagated to children via cloneElement (overrides per-child size). |
withRing | boolean | true | Show ring-neutral-50 separator on each child. |
total | number | derived | Override the total count (useful when you slice children client-side). |
className | string | — | Merged via tailwind-merge. |
children | Avatar[] | (required) | Avatar siblings. |
name, uppercased. "Jane Doe" → "JD". "Madonna" → "M". " jane van der meer " → "JV".<img> renders, it has alt="" (decorative) — the parent <span> carries the accessible name via aria-label. Avoids double-announce in screen readers.color and tone are constrained at the type level to the tokens declared in @dashforge/tw-tokens. Adding a new palette key in the tokens package immediately surfaces as a new valid color value here.sx / className override on the no-image background. The constraint is on color/tone props only — the className escape hatch is unrestricted.