Koala logo Design

Avatar pickers

The avatar picker pattern used on user profile and account settings pages. Supports uploading a new image and removing an existing one, with an initials fallback when no avatar is set.

Without avatar (initials fallback)

When no avatar is uploaded, the Large avatar displays initials. Only the upload button is shown.

SJ

JPEG, PNG, WebP, or GIF. Max 2MB.

<div id="avatar-picker">
    <div class="flex flex-col sm:flex-row items-center gap-4">
        <div class="shrink-0">
            <koala-avatar size="Large"
                          user-id="@Model.Id"
                          first-name="@Model.FirstName"
                          last-name="@Model.LastName"
                          has-avatar="false" />
        </div>
        <div class="flex flex-col sm:flex-row gap-3
                    w-full sm:w-auto">
            <form method="post"
                  asp-page-handler="UploadAvatar"
                  enctype="multipart/form-data"
                  x-target="avatar-picker"
                  x-data="{ fileName: '' }">
                <label class="cursor-pointer inline-flex
                              items-center justify-center
                              text-white bg-brand border
                              border-transparent
                              hover:bg-brand-strong
                              font-medium rounded-lg px-4 py-2
                              w-full sm:w-auto">
                    <span x-text="fileName || 'Upload image'">
                    </span>
                    <input type="file" name="avatar"
                           accept="image/jpeg,image/png,
                                  image/webp,image/gif"
                           class="hidden"
                           x-on:change="fileName =
                               $el.files[0]?.name || '';
                               if (fileName) {
                                   $el.closest('form')
                                      .requestSubmit();
                               }" />
                </label>
            </form>
        </div>
    </div>
    <p class="mt-3 text-sm text-gray-500
              dark:text-gray-400">
        JPEG, PNG, WebP, or GIF. Max 2MB.
    </p>
</div>

With avatar (image + remove)

When an avatar exists, both the upload and remove buttons are shown. The remove button uses the Danger Outlined variant.

Sarah Johnson

JPEG, PNG, WebP, or GIF. Max 2MB.

<div id="avatar-picker">
    <div class="flex flex-col sm:flex-row items-center gap-4">
        <div class="shrink-0">
            <koala-avatar size="Large"
                          user-id="@Model.Id"
                          first-name="@Model.FirstName"
                          last-name="@Model.LastName"
                          has-avatar="true" />
        </div>
        <div class="flex flex-col sm:flex-row gap-3
                    w-full sm:w-auto">
            <!-- Upload form -->
            <form method="post"
                  asp-page-handler="UploadAvatar"
                  enctype="multipart/form-data"
                  x-target="avatar-picker"
                  x-data="{ fileName: '' }">
                <label class="cursor-pointer inline-flex
                              items-center justify-center
                              text-white bg-brand
                              font-medium rounded-lg px-4 py-2
                              w-full sm:w-auto">
                    <span x-text="fileName || 'Upload image'">
                    </span>
                    <input type="file" name="avatar"
                           accept="image/jpeg,image/png,
                                  image/webp,image/gif"
                           class="hidden"
                           x-on:change="fileName =
                               $el.files[0]?.name || '';
                               if (fileName) {
                                   $el.closest('form')
                                      .requestSubmit();
                               }" />
                </label>
            </form>

            <!-- Remove form -->
            <form method="post"
                  asp-page-handler="RemoveAvatar"
                  x-target="avatar-picker">
                <button type="submit"
                        koala-btn="Danger"
                        koala-btn-variant="Outlined"
                        class="w-full sm:w-auto">
                    Remove
                </button>
            </form>
        </div>
    </div>
    <p class="mt-3 text-sm text-gray-500
              dark:text-gray-400">
        JPEG, PNG, WebP, or GIF. Max 2MB.
    </p>
</div>

Tray vs full page mode

The avatar picker partial detects whether it is rendered inside a side tray or as a full page. In tray mode, the form uses x-target="avatar-picker" for AJAX updates. In full page mode, it uses formnoajax for a standard form submission.

@{
    var isTray = alpineTarget.Contains("side-tray-content")
        || alpineTarget.Contains("avatar-picker");
}

@if (isTray)
{
    <!-- AJAX: x-target="avatar-picker" on form -->
    <form method="post"
          asp-page-handler="UploadAvatar"
          enctype="multipart/form-data"
          x-target="avatar-picker">
        ...
    </form>
}
else
{
    <!-- Full page: formnoajax -->
    <form method="post"
          asp-page-handler="UploadAvatar"
          enctype="multipart/form-data"
          formnoajax>
        ...
    </form>
}

Key rules

  • Always use the Large avatar size (w-20 h-20) in the picker
  • The upload button is a styled <label> wrapping a hidden file input
  • The file input auto-submits when a file is selected via x-on:change
  • The label text updates to show the selected filename via x-text
  • Remove button only appears when has-avatar is true
  • Accept image/jpeg,image/png,image/webp,image/gif only
  • The form must use enctype="multipart/form-data"
  • The entire picker is wrapped in id="avatar-picker" for AJAX targeting
  • Layout: flex-col sm:flex-row for avatar + buttons, stacks on mobile