Skip to main content
WireKit
Copy for LLM

Profile

A compact avatar + name combo for the trailing slot of a <x-wirekit::header> or the leading slot of a user menu. Profile is structural — it lays out an avatar image and a name side-by-side without imposing a link target or a click behavior. Wrap it in an <a>, a <button>, or a <x-wirekit::dropdown.trigger> when you need interaction.

Basic Usage

Pass avatar for an image, name for text, or both for a combined mark. The avatar is decorative (alt="") — the name text provides the accessible label when present.

Avatar + name
Jane Doe
Name only
Jane Doe
Avatar only

Custom Content

If you need more than an avatar and name (e.g. a role badge, a status indicator, a chevron), pass arbitrary children. Children render after the avatar and name — they are additive, not replacements.

Profile with status badge
Jane Doe Online
Profile with role
Admin User

Owner

Props

Prop Type Default Description
avatar string|array|null null URL of an avatar image, or ['src' => …, 'initials' => …, 'alt' => …]. Rendered at h-8 w-8 with rounded-full object-cover. Decorative — alt="" unless the array supplies one. With no src, the initials render in a token-colored circle instead.
name string|null null Profile name text. Rendered at --text-wk-sm with body-weight font.
as 'div' | 'button' 'div' The element to render. button gives you a real control: the browser supplies Enter and Space activation and the button role, with no JavaScript involved. Prefer it over interactive whenever the profile is itself the thing being clicked. Keep div when the profile sits inside something that is already a control — a button inside a button is invalid HTML.
interactive bool false Turns a div profile into a focusable button-like element with role="button" + tabindex="0" plus Enter / Space keyboard handlers that synthesize a click. Use it when the surrounding markup rules out a real <button>; otherwise reach for as="button", which gets the same behavior from the browser instead of from Alpine. Adds a focus-visible ring matching the canonical button focus state. Has no effect on as="button", which is already a control. Default false preserves the presentational <div> byte-for-byte.
scope string|null null Named personalization scope for block-level class overrides.

When both avatar and name are omitted, the component renders an empty flex container — pass arbitrary children via the default slot for full control.

Interactive profile inside a dropdown trigger

The most common interactive use case — profile menu in a navbar. Without interactive, the <div> has no focusable child, so keyboard users can Tab past it without opening the menu.

A profile that opens an account menu
Jane Doe

The same menu with a real button

as="button" replaces the synthesized keyboard model with the browser's own. The markup is one attribute different and the rendering is identical; what changes is that the control is a button in the served HTML, before any JavaScript runs.

A profile button that opens an account menu

Accessibility

  • The avatar <img> is decorative: alt="" so the accessible name comes from the name text or surrounding interactive element
  • By default Profile is not interactive — it renders a plain <div>. Give it as="button" when the profile is the control, or wrap it in an <a> / <button> / dropdown trigger when the surrounding element is
  • as="button" is the accessible default for a clickable profile: Space and Enter both activate it, and it is a button to assistive tech from the first paint. interactive synthesizes the same two keys from Alpine handlers, which means they do nothing until Alpine has booted — use it only where a real <button> is not possible, such as inside another control
  • When the profile is used inside an interactive wrapper (link/button/trigger), ensure the wrapper has a clear accessible name — either from the visible name text or via an explicit aria-label on the wrapper
<x-wirekit::dropdown.trigger>
    <x-wirekit::profile avatar="/me.jpg" name="Jane Doe" />
</x-wirekit::dropdown.trigger>

Keyboard Interaction

The default <div> is presentational and takes no focus, so there is nothing to operate.

Shape Focus Keys
default not focusable
as="button" in the tab order Enter and Space activate it (from the browser)
interactive in the tab order via tabindex="0" Enter and Space activate it (from Alpine, so only once Alpine has booted)

Pitfalls

  • Don't reach for interactive when as="button" will do. Both make the profile clickable, but only the button is one before Alpine has loaded, and only the button is announced with its role in the served HTML.
  • Don't put a link or another button in the slot of an as="button" profile. A control nested inside a control is invalid HTML and unreachable by keyboard in practice. Keep the default div for that layout and make the inner element the control.
  • Pass avatar as an array when you want an initials fallback. A bare string is treated as an image URL; ['src' => …, 'initials' => …] lets the component fall back to initials when the image is absent.

Design Tokens

Token Used for
--color-wk-text Name text color
--gap-wk-sm Gap between avatar and name
--text-wk-sm Name font size
--font-wk-body-weight Name font weight

See Also

  • Header — typical parent for Profile in the trailing slot
  • Brand — leading-slot counterpart
  • Dropdown — wrap Profile in a trigger for a user menu

Was this page helpful?

Voting requires cookies or local storage. What we store