Skip to content

Avatar

Avatar and AvatarGroup render people, teams, or accounts with a consistent Bootstrap-friendly shape. Use images when available, and fall back to initials when not.

Import

from faststrap import Avatar, AvatarGroup

Basic Usage

Avatar(name="Ada Lovelace")
Avatar(name="Grace Hopper", src="/static/grace.jpg")

With Presence

Avatar(
    name="Katherine Johnson",
    status="online",
    status_variant="success",
)

Avatar Groups

AvatarGroup(
    Avatar(name="Ada Lovelace"),
    Avatar(name="Grace Hopper"),
    Avatar(name="Katherine Johnson"),
    max_visible=2,
    total=5,
)

AvatarGroup shows the visible avatars and adds a +N counter when there are more people than the visible limit.

Parameters

Avatar

Param Type Default Description
name str \| None None Display name used for title, ARIA label, and generated initials.
src str \| None None Optional image URL.
alt str \| None None Image alt text. Defaults to name.
initials str \| None None Explicit initials override.
size xs \| sm \| md \| lg \| xl md Avatar size.
shape circle \| rounded \| square circle Avatar shape.
variant str secondary Bootstrap text/background variant for initials.
status str \| None None Optional status label. Common values: online, busy, away, offline.
status_variant str \| None None Bootstrap variant for the status dot.
**kwargs Any Extra attributes.

AvatarGroup

Param Type Default Description
*avatars Any Avatar components.
max_visible int \| None None Maximum avatars to show before adding a +N counter.
total int \| None None Total people count when not all avatars are passed.
size xs \| sm \| md \| lg \| xl md Size for the generated +N counter avatar.
overlap bool True Overlap avatars with negative margin.
**kwargs Any Extra group attributes.

faststrap.components.display.avatar.Avatar(name=None, *, src=None, alt=None, initials=None, size='md', shape='circle', variant='secondary', status=None, status_variant=None, **kwargs)

Render a user avatar from an image or initials.

Source code in src/faststrap/components/display/avatar.py
@register(category="display")
@beta
def Avatar(
    name: str | None = None,
    *,
    src: str | None = None,
    alt: str | None = None,
    initials: str | None = None,
    size: AvatarSize = "md",
    shape: AvatarShape = "circle",
    variant: str = "secondary",
    status: str | None = None,
    status_variant: str | None = None,
    **kwargs: Any,
) -> Span:
    """Render a user avatar from an image or initials."""
    dimension = AVATAR_SIZES.get(size, AVATAR_SIZES["md"])
    user_cls = kwargs.pop("cls", "")
    classes = [
        "faststrap-avatar",
        "d-inline-flex",
        "align-items-center",
        "justify-content-center",
        "position-relative",
        "fw-semibold",
        "text-uppercase",
        "overflow-hidden",
        _shape_class(shape),
    ]
    if not src:
        classes.extend([f"text-bg-{variant}"])

    attrs: dict[str, Any] = {
        "cls": merge_classes(" ".join(classes), user_cls),
        "style": {
            "width": dimension,
            "height": dimension,
            "min-width": dimension,
            "font-size": f"calc({dimension} * 0.38)",
        },
        "title": name,
        "aria_label": alt or name or "Avatar",
    }
    attrs.update(convert_attrs(kwargs))

    if src:
        content: Any = Img(
            src=src,
            alt=alt or name or "",
            cls="w-100 h-100 object-fit-cover",
        )
    else:
        content = Span(initials or _initials_from_name(name), aria_hidden="true")

    children = [content]
    if status:
        dot_variant = status_variant or {
            "online": "success",
            "busy": "danger",
            "away": "warning",
            "offline": "secondary",
        }.get(status, "secondary")
        children.append(
            Span(
                cls=(
                    "position-absolute bottom-0 end-0 rounded-circle "
                    f"bg-{dot_variant} border border-2 border-body"
                ),
                style={
                    "width": "25%",
                    "height": "25%",
                    "min-width": "0.55rem",
                    "min-height": "0.55rem",
                },
                aria_label=status,
            )
        )

    return Span(*children, **attrs)

faststrap.components.display.avatar.AvatarGroup(*avatars, max_visible=None, total=None, size='md', overlap=True, **kwargs)

Render a compact group of avatars.

Source code in src/faststrap/components/display/avatar.py
@register(category="display")
@beta
def AvatarGroup(
    *avatars: Any,
    max_visible: int | None = None,
    total: int | None = None,
    size: AvatarSize = "md",
    overlap: bool = True,
    **kwargs: Any,
) -> Div:
    """Render a compact group of avatars."""
    visible = list(avatars)
    hidden_count = 0
    if max_visible is not None and max_visible >= 0:
        hidden_count = max(0, len(visible) - max_visible)
        visible = visible[:max_visible]

    if total is not None:
        hidden_count = max(hidden_count, total - len(visible))

    user_cls = kwargs.pop("cls", "")
    attrs: dict[str, Any] = {
        "cls": merge_classes("faststrap-avatar-group d-inline-flex align-items-center", user_cls),
        "role": "group",
        "aria_label": "Avatar group",
    }
    attrs.update(convert_attrs(kwargs))

    wrapped = []
    for index, avatar in enumerate(visible):
        style = {"z-index": str(len(visible) - index)}
        if overlap and index > 0:
            style["margin-left"] = "-0.5rem"
        wrapped.append(
            Span(
                avatar,
                cls="d-inline-flex rounded-circle border border-2 border-body",
                style=style,
            )
        )

    if hidden_count > 0:
        counter_style = {"margin-left": "-0.5rem"} if overlap and wrapped else {}
        wrapped.append(
            Span(
                Avatar(initials=f"+{hidden_count}", size=size, variant="light", shape="circle"),
                cls="d-inline-flex rounded-circle border border-2 border-body",
                style=counter_style,
            )
        )

    return Div(*wrapped, **attrs)