Avatar

The Avatar component is a flexible UI element used to display user profile pictures or initials. It includes built-in support for proxying Google avatar URLs to avoid 429 Too Many Requests errors and handles fallback states gracefully.

Overview

When users sign in with Google, their profile pictures are hosted on googleusercontent.com. Repeatedly loading these images across different client instances can trigger rate limits. The system mitigates this by:
  1. Backend Proxying: A Bun backend service (/api/v1/users/avatar) fetches and caches the image bytes.
  2. Frontend Rewriting: A utility rewrites Google avatar URLs to point to our proxy.
  3. Graceful Fallback: If the image fails to load, it falls back to user initials.

Usage

Basic Usage

import { Avatar } from "@gremlin/ui";
import { getAvatarUrl } from "@gremlin/core";

const UserProfile = (props) => {
  return (
    <Avatar
      src={getAvatarUrl(props.user.image)}
      fallback={props.user.name?.[0]}
      size="md"
    />
  );
};

Sizes

The component supports multiple pre-defined sizes using the size prop:
SizeClassDescription
xsh-6 w-6Extra small (sidebar, inline)
smh-8 w-8Small
mdh-10 w-10Medium (Default)
lgh-12 w-12Large
xlh-16 w-16Extra large (profile pages)

Proxy System

The getAvatarUrl utility identifies Google-hosted images and rewrites them to use the backend proxy.

How it works

  1. Checks if the URL ends with .googleusercontent.com or .ggpht.com.
  2. Encodes the original URL as a query parameter.
  3. Returns a URL pointing to ${API_URL}/api/v1/users/avatar?url=....

Backend Implementation

The backend proxy:
  • Validates that the requested URL is a Google-owned host.
  • Fetches the image once from Google.
  • Caches the bytes in-memory for 6 hours.
  • Returns appropriate Cache-Control and ETag headers for browser-level caching.

Component API

Props

PropTypeDefaultDescription
srcstringundefinedThe image URL. Use getAvatarUrl() to enable proxying.
altstring"Avatar"Alt text for the image.
fallbackstringundefinedContent to show if the image is missing or fails to load.
size"xs" "sm" "md" "lg" "xl""md"The visual size of the avatar.
classstringundefinedAdditional CSS classes for the container.
  • frontend/solidstart/packages/ui/src/components/ui/Avatar.tsx
  • frontend/solidstart/packages/core/src/utils/avatar.ts
  • backend/bun/apps/monolith/src/services/users/api.ts