Askr documentation
UI & Components

Avatar and Item

Avatar and Item: anatomy, keyboard behavior, state, and theming in Askr.

Example

import { Avatar, AvatarFallback, AvatarImage, Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from '@askrjs/themes/components';

<Item>
  <ItemMedia><Avatar><AvatarImage src={owner.avatarUrl} alt="" /><AvatarFallback>{owner.initials}</AvatarFallback></Avatar></ItemMedia>
  <ItemContent><ItemTitle>{owner.name}</ItemTitle><ItemDescription>{owner.role}</ItemDescription></ItemContent>
</Item>

Published props

Generated from the TypeScript declarations shipped by the installed package. Named types in the Type column define the accepted values.

AvatarAsChildProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
asChildasChild: true;——
childrenchildren: JSXElement;——
idid?: string | undefined;——
refref?: Ref<Element>;——

AvatarFallbackAsChildProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
asChildasChild: true;——
childrenchildren: JSXElement;——
refref?: Ref<Element>;——

AvatarFallbackOwnProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
childrenchildren?: unknown;——

AvatarFallbackProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
asChildasChild?: false | undefined;——
childrenchildren?: unknown;——
refref?: Ref<HTMLSpanElement>;——

AvatarImageOwnProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
altalt: string;——
onLoadingStatusChangeonLoadingStatusChange?: ((status: AvatarLoadingStatus) => void) | undefined;——
srcsrc?: string | undefined;——

AvatarImageProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
altalt: string;——
onLoadingStatusChangeonLoadingStatusChange?: ((status: AvatarLoadingStatus) => void) | undefined;——
refref?: Ref<HTMLImageElement>;——
srcsrc?: string | undefined;——

AvatarOwnProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
childrenchildren?: unknown;——
idid?: string | undefined;——

AvatarProps

Import from @askrjs/themes/avatar.

PropTypeDefaultDescription
asChildasChild?: false | undefined;——
childrenchildren?: unknown;——
idid?: string | undefined;——
refref?: Ref<HTMLSpanElement>;——

Purpose

Avatar and Item solve two different problems that tend to show up together: Avatar renders a person or entity's image with a graceful fallback, and Item lays out a single row of content — icon or avatar, title, description, and trailing actions — the kind of row you see in a user list, a notification, or a search result. Avatar is a real headless primitive from @askrjs/ui/avatar with a themed skin on top; Item exists only in @askrjs/themes, since a static content row doesn't need behavior of its own beyond what its interactive children provide.

Install and import

Import Avatar, AvatarImage, and AvatarFallback from @askrjs/ui/avatar if you're building your own visual treatment, or from @askrjs/themes/avatar for the pre-styled version — both re-export the same underlying components, so you're choosing between headless and themed, not between two different APIs. Item, ItemGroup, ItemHeader, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, and ItemFooter all come from @askrjs/themes/item, since there's no @askrjs/ui counterpart to import instead.

Live examples

A typical avatar is <Avatar><AvatarImage src={url} alt={name} /><AvatarFallback>{initials}</AvatarFallback></Avatar> — the fallback renders automatically while the image is loading or if it errors. Drop that into an ItemMedia slot inside an Item, pair it with ItemContent holding ItemTitle and ItemDescription, and add ItemActions for a trailing button or menu — that's the standard "user row" pattern used across account lists, comment threads, and search results. Wrap several Items in ItemGroup when they belong together as a list.

Anatomy

Avatar is three pieces: the Avatar root (a span), AvatarImage (an img with required alt), and AvatarFallback (a span shown before the image loads or after it errors). Item is a row split into ItemMedia (for the avatar or icon), ItemContent (holding ItemTitle and ItemDescription), and optional ItemHeader/ItemFooter/ItemActions slots — ItemGroup wraps a set of Items into a list container.

State model

Avatar tracks one real piece of state: AvatarLoadingStatus, typed as 'idle' | 'loading' | 'loaded' | 'error', exposed through AvatarImage's onLoadingStatusChange callback so you can react to load failures yourself. Item's state is purely presentational — active?: boolean and variant?: 'default' | 'outline' | 'muted' control appearance, but Item doesn't manage selection or interaction state; if a row needs to respond to clicks or track selected-ness, that logic lives in your own component or in whatever interactive element you put inside it.

Keyboard and accessibility

AvatarImage requires an alt prop at the type level — there's no way to render an image avatar without supplying alt text, which the a11y contract documents as requiresAlt: true. AvatarFallback is marked visibleBeforeImageLoad: true in that same contract, so screen reader users don't hit a blank state while the image is in flight. Item itself has no keyboard model since it's not a control — if a row is meant to be actionable, put a real <button> or link inside ItemActions or make the whole row an anchor rather than relying on a synthetic click handler.

Styling and tokens

Target the published data-slot and data-state hooks rather than private child structure. Item size and variant attributes select theme spacing and presentation; inspect the resulting DOM and styles when composing a custom theme.

API

AvatarImageProps accepts src?: string, a required alt: string, and onLoadingStatusChange?: (status: AvatarLoadingStatus) => void, layered on top of native img attributes (minus the ones it manages itself). AvatarProps and AvatarFallbackProps are otherwise just children plus standard box props. Item takes active?: boolean, size?: 'default' | 'sm' | 'xs', and variant?: 'default' | 'outline' | 'muted' on top of the generic CatalogComponentProps (as, asChild, class, children) shared by every themed catalog component; the surrounding Item* parts (ItemGroup, ItemHeader, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, ItemFooter) only take that same generic prop set.

Edge cases

If AvatarImage never resolves — a broken URL, a slow network, an offline user — the fallback stays visible indefinitely, so make sure your AvatarFallback content (initials, a generic icon) is something reasonable to show long-term, not just a placeholder. Long titles or descriptions inside ItemContent will wrap by default; if you need truncation, that's a CSS concern you own, same as Card. An Item with no ItemMedia still lays out correctly — the media slot is optional, not required scaffolding.

Card is the right fit once a row grows past "single line of content plus actions" into something with its own header, body, and footer regions. Table and Data Table are worth checking when you're rendering many rows of structured, sortable data rather than a loose list. NavigationMenu and Sidebar's SidebarMenuItem cover navigation-flavored rows, which overlap with Item conceptually but carry their own interaction model.