User Button 01

A user avatar button with a dropdown menu for authentication and account actions.

Acme

Installation

CLI

Install the component using the StarUI CLI:

star add user-button-01

Source

Full source code for this block.

user_button.py
from components.avatar import Avatar, AvatarFallback, AvatarImage
from components.dropdown_menu import (
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuLabel,
    DropdownMenuSeparator,
    DropdownMenuTrigger,
)
from components.utils import cn
from starhtml import FT, Icon, P, Span

__metadata__ = {
    "description": "User avatar button with dropdown menu for auth actions",
    "handlers": ["position"],
}


def UserButton(
    *children,
    name: str = "",
    email: str = "",
    avatar_src: str = "",
    avatar_fallback: str = "",
    show_name: bool = False,
    signal: str = "",
    side: str = "bottom",
    align: str = "end",
    side_offset: int = 4,
    cls: str = "",
    **kwargs,
) -> FT:
    """User avatar button with dropdown menu for account/auth actions."""

    if not avatar_fallback and name and name.strip():
        parts = name.split()
        avatar_fallback = (parts[0][0] + (parts[-1][0] if len(parts) > 1 else "")).upper()

    avatar = Avatar(
        AvatarImage(src=avatar_src, alt="") if avatar_src else None,
        AvatarFallback(avatar_fallback) if avatar_fallback else None,
        cls="size-8",
    )

    if show_name and name:
        trigger_content = Span(
            avatar,
            Span(name, cls="max-w-[150px] truncate"),
            Icon("lucide:chevron-down", cls="size-3.5 shrink-0 opacity-50"),
            cls="flex items-center gap-2",
        )
        trigger_cls = cn(
            "relative h-auto cursor-pointer rounded-full py-1 pr-3 pl-1 ring-offset-background transition-colors",
            "hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
            "aria-expanded:bg-accent",
            cls,
        )
    else:
        trigger_content = avatar
        trigger_cls = cn(
            "relative h-8 w-8 cursor-pointer rounded-full px-0",
            "ring-offset-background transition-shadow",
            "hover:ring-2 hover:ring-ring/50 hover:ring-offset-2",
            "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
            "aria-expanded:ring-2 aria-expanded:ring-ring aria-expanded:ring-offset-2",
            cls,
        )

    trigger_label = f"{name}'s account menu" if name else "Account menu"

    header_parts = []
    if name or email:
        header_parts.append(
            DropdownMenuLabel(
                P(name, cls="truncate text-sm leading-none font-semibold") if name else None,
                P(email, cls="truncate text-xs leading-none text-muted-foreground") if email else None,
                cls="flex flex-col gap-1.5 font-normal",
            )
        )
        header_parts.append(DropdownMenuSeparator())

    return DropdownMenu(
        DropdownMenuTrigger(
            trigger_content,
            variant="ghost",
            aria_label=trigger_label,
            cls=trigger_cls,
        ),
        DropdownMenuContent(
            *header_parts,
            *children,
            side=side,
            align=align,
            side_offset=side_offset,
            cls="min-w-48",
        ),
        signal=signal,
        **kwargs,
    )

Dependencies

This block composes the following components: