# Avatar A circular user avatar. Shows an image when a `src` URL is provided; falls back to a text/initials span otherwise. --- ## HTML structure ``` span.relative.flex.{size classes}.shrink-0.overflow-hidden.rounded-full img[src, alt, class] ← when src is provided span.flex.items-center... ← fallback when no src {fallback text} ``` --- ## CSS mechanics | Class | Effect | |---|---| | `rounded-full overflow-hidden` | Clips content to a circle | | `aspect-square h-full w-full object-cover` | Image fills the circle without distortion | | `bg-muted text-muted-foreground` | Neutral background for the initials fallback | | Size `h-8 w-8` / `h-10 w-10` / `h-14 w-14` / `h-20 w-20` | sm / default / lg / xl | --- ## Constructor signature ```csharp public Avatar( string fallback, string? src = null, string size = "default") ``` | Parameter | Description | |---|---| | `fallback` | Text shown when no `src` is given; also used as `alt` text on the image | | `src` | Optional image URL | | `size` | `"sm"` / `"default"` / `"lg"` / `"xl"` | --- ## Usage examples ### Initials avatar ```csharp new Avatar(fallback: "JD") new Avatar(fallback: "JD", size: "lg") ``` ### Image avatar with fallback ```csharp new Avatar(fallback: "Jane Doe", src: "/avatars/jane.jpg", size: "default") ``` ### Sizes ```csharp new Avatar(fallback: "SM", size: "sm") // 32×32 new Avatar(fallback: "DF", size: "default") // 40×40 new Avatar(fallback: "LG", size: "lg") // 56×56 new Avatar(fallback: "XL", size: "xl") // 80×80 ``` ### Inside a user card ```csharp var avatar = new Avatar(fallback: user.Initials, src: user.AvatarUrl, size: "lg"); // In a page's RenderUserCard override: protected override void RenderUserAvatar(HtmxRenderContext ctx) => avatar.Render(ctx.Next()); ``` --- ## Tips and tricks - Compute initials before constructing the Avatar — the component does not extract them from a full name. See `MainLayout`'s `GetInitials` helper for a reference implementation. - Always provide `fallback` even when you also provide `src` — it serves as the `alt` attribute for accessibility. - The Avatar does not handle image load errors. If you need a graceful image fallback on 404, add an `onerror="this.style.display='none'"` attribute by embedding it in the `src` or use `hxAttrs` in a subclassed version. - For a group of overlapping avatars (avatar stack), wrap several Avatars in a flex container with negative margin: `
`. --- ## Complete page example **`Templates/ProfilePage.htmx`** ```html
$$UserAvatar$$

$$DisplayName$$

$$Email$$

Member since $$JoinDate$$

``` **`Templates/ProfilePage.htmx.cs`** ```csharp namespace Htmx.ApiDemo.Templates; public sealed class ProfilePage : ProfilePageBase { private readonly IHtmxComponent _avatar; private readonly byte[] _displayName; private readonly byte[] _email; private readonly byte[] _joinDate; public ProfilePage(AppUser user) { _avatar = new Components.Avatar( fallback: GetInitials(user.DisplayName), size: "lg"); _displayName = (user.DisplayName ?? "Unknown").ToUtf8Bytes(); _email = user.Email.ToUtf8Bytes(); _joinDate = user.CreatedAt.ToString("MMMM yyyy").ToUtf8Bytes(); } private static string GetInitials(string? name) { if (string.IsNullOrWhiteSpace(name)) return "?"; var parts = name.Split(' ', StringSplitOptions.RemoveEmptyEntries); return parts.Length >= 2 ? $"{parts[0][0]}{parts[^1][0]}" : name[..1].ToUpperInvariant(); } protected override void RenderUserAvatar(HtmxRenderContext ctx) => _avatar.Render(ctx.Next()); protected override void RenderDisplayName(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_displayName); protected override void RenderEmail(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_email); protected override void RenderJoinDate(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_joinDate); } ``` **GET handler** ```csharp [Handler] [MapGet("/profile")] public static partial class GetProfileHandler { public record Query(); private static async Task HandleAsync( Query _, HttpContext ctx, MongoDbService db, CancellationToken ct) { var email = ctx.User.FindFirst(ClaimTypes.Email)?.Value ?? ""; var user = await db.FindByNormalizedEmailAsync(email.ToUpperInvariant(), ct); if (user is null) return Results.Redirect("/login"); return await ctx.WriteHtmxPage(new ProfilePage(user), title: "Profile"); } } ```