Skip to content

LayrzAvatar

Kenny Mochizuki Escalona edited this page Aug 18, 2026 · 9 revisions

LayrzAvatar

A static display component that renders a user avatar in one of five forms: image (URL or base64), icon, emoji, or initials generated from a name. The avatar is always a rounded box using the r12 radius token, consistent with LayrzCard and LayrzAlert, and carries a fixed tokens.shadow.compact1 drop shadow in all render modes.

Metadata
Mirrors: ThemedAvatar (layrz_theme)
Phase: M2 (Core primitives)
Domain: Display
Primitive: Hand-rolled (ClipRRect + Container + Image + Icon + Text)
Status: Confirmed scope.


Overview

LayrzAvatar renders a static, non-interactive avatar display. It is display-only and does not support interaction callbacks (onTap, onLongPress, etc.). Callers who need interactivity should wrap the avatar in a GestureDetector or similar widget themselves. This keeps the API minimal and separation of concerns clear.

The avatar resolves what to display using a strict fallback order:

  1. Image from a named constructor (.image()) — renders from URL or base64
  2. Icon from a named constructor (.icon()) — renders from LayrzIcon
  3. Emoji from a named constructor (.emoji()) — renders a Unicode glyph
  4. Initials from a named constructor (.initials()) — renders from nameText
  5. Avatar descriptor from Avatar model (avatar parameter) — resolves by AvatarType
  6. Fallback to initials — from nameText when the avatar is null or missing

Design Principles

  • Static display only: No interaction callbacks. Wrap with GestureDetector if needed.
  • Multiple render modes: Image (URL/base64), icon, emoji, or initials — all from a single Avatar object.
  • Smart fallback: Falls through gracefully when any mode's required field is missing.
  • Fixed sizing: A single size parameter defines both width and height.
  • Consistent rounding: Always a rounded box using the r12 radius token, matching other surface components.
  • Color-aware text: Text color (for initials and emoji) is automatically contrasted against the background for readability.
  • Fixed drop shadow: Every avatar carries a fixed tokens.shadow.compact1 drop shadow in all modes. This shadow is intentionally not configurable.

API Structure

Core Constructor

class LayrzAvatar extends StatelessWidget {
  /// Avatar descriptor from layrz_sdk; its `type` selects what is rendered.
  ///
  /// When null, falls back to initials from [nameText]. When the type's required
  /// field is missing (e.g., [AvatarType.url] but `url` is null), also falls back
  /// to initials.
  final Avatar? avatar;

  /// Name text from which initials are generated when [avatar] is null, has type
  /// [AvatarType.none], or is missing the field its type requires.
  ///
  /// If null and no usable avatar is available, displays `"NA"` as a placeholder.
  final String? nameText;

  /// Width and height of the avatar in logical pixels.
  ///
  /// Defaults to 40. The avatar is always square with rounded corners, so this
  /// single value defines both dimensions.
  final double size;

  /// Background fill color of the avatar.
  ///
  /// Defaults to the primary token color when null. Ignored when rendering an
  /// image (images render on a white background to ensure visibility when the
  /// source has transparency).
  final Color? color;

  /// Creates a new [LayrzAvatar].
  ///
  /// Renders the avatar described by the [Avatar] object from layrz_sdk.
  /// Falls back to initials from [nameText] when the avatar is null or missing.
  /// At least one of [avatar] or [nameText] should be provided for useful output.
  const LayrzAvatar({
    super.key,
    this.avatar,
    this.nameText,
    this.size = 40,
    this.color,
  });
}

Named Constructors

.image()

Renders an avatar from an image source (URL or base64).

const LayrzAvatar.image({
  required String source,
  this.size = 40,
});
  • source: An http(s) URL, a data: URI, or a bare base64 string. Routed to LayrzImage.
  • Background: White, ensuring visibility when the image source has transparency.

.icon()

Renders an avatar from a LayrzIcon (from layrz_icons).

const LayrzAvatar.icon({
  required LayrzIcon icon,
  this.size = 40,
  this.color,
});
  • icon: The LayrzIcon to display (accessed via its .iconData getter).
  • Color: Defaults to the primary token color.
  • Icon size: 70% of size.

.emoji()

Renders an avatar from a Unicode emoji glyph.

const LayrzAvatar.emoji({
  required String emoji,
  this.size = 40,
});
  • emoji: A single Unicode emoji or emoji sequence.
  • Background: White.
  • Emoji size: 60% of size.

.initials()

Renders an avatar from generated initials.

const LayrzAvatar.initials({
  required this.nameText,
  this.size = 40,
  this.color,
});
  • nameText: The name from which initials are derived.
  • Color: Defaults to the primary token color.

Avatar Type Resolution (from layrz_sdk)

When the main constructor receives an Avatar object, the type field selects the rendering:

Type Behaviour Fallback
AvatarType.url Displays the image from avatar.url via LayrzImage Initials from nameText if url is null
AvatarType.base64 Displays the image from avatar.base64 via LayrzImage Initials from nameText if base64 is null
AvatarType.icon Displays the icon from avatar.icon (a LayrzIcon) Initials from nameText if icon is null
AvatarType.emoji Displays the emoji from avatar.emoji Initials from nameText if emoji is null
AvatarType.none Falls back to initials from nameText "NA" if nameText is null/empty

Initials Generation

The initials algorithm (when falling back to text):

  1. Strip all non-alphanumeric characters from the input name.
  2. If empty, display "NA" (Not Available).
  3. If one character, display that character.
  4. If two or more characters, display the first two characters in uppercase.

Known limitation: This algorithm is not Unicode-aware (combining characters, non-Latin scripts, ligatures are treated as separate characters). This is an accepted limitation, not a bug to solve. Most real-world use cases involve Latin-script names.


Sizing and Styling

  • Size: A single size parameter (default 40) defines both width and height.
  • Shape: Always a rounded box using the r12 radius token, consistent with LayrzCard, LayrzAlert, and the dropdown panel.
  • Background color: Defaults to the primary token color when null. For images, always white to ensure visibility when the source has transparency.
  • Text color (for initials/icons): Automatically contrasted against the background using a luminance heuristic — black text for light backgrounds, white text for dark backgrounds.
  • Fixed drop shadow: Every avatar carries tokens.shadow.compact1 as a fixed drop shadow in all render modes (initials, icon, emoji, URL/base64 image). This is the small-component shadow ramp used by LayrzButton, chosen because a soft low-offset shadow disappears at avatar sizes; compact shadows provide clear separation at 40px width. This shadow is intentionally not configurable — it is part of the avatar's baseline visual treatment.

Image Loading

The .image() constructor and URL/base64 types in the Avatar model route image rendering through LayrzImage. See LayrzImage for details on:

  • Supported source formats (http(s) URLs, data-URIs, bare base64, asset paths)
  • SVG detection and handling
  • Placeholder and fallback rendering
  • Base64 decoding cache and eviction policy

Relationship to Input Components

  • LayrzAvatarInput — Input-side component for selecting an avatar from a system image picker.
  • LayrzDynamicAvatarInput — Input-side component for selecting an avatar from multiple sources (URL, base64, icon, emoji).

Examples

From Avatar Model (layrz_sdk)

// The Avatar model comes from layrz_sdk
final user = Avatar(
  type: AvatarType.url,
  url: 'https://example.com/user.png',
);

LayrzAvatar(
  avatar: user,
  nameText: 'Jane Smith', // Fallback if URL fails to load
  size: 48,
)

Image Avatar

LayrzAvatar.image(
  source: 'https://cdn.layrz.com/resources/com.layrz.one/favicon/normal.png',
  size: 56,
)

Icon Avatar

LayrzAvatar.icon(
  icon: LayrzIcons.solarUserBold,
  size: 40,
  color: context.tokens.colors.info,
)

Emoji Avatar

LayrzAvatar.emoji(
  emoji: '🎨',
  size: 48,
)

Initials Avatar

LayrzAvatar.initials(
  nameText: 'Alice Johnson',
  size: 40,
  color: context.tokens.colors.success,
)

Fallback Chain

// Avatar model with missing `url`; falls back to initials
final incompleteAvatar = Avatar(
  type: AvatarType.url,
  url: null, // Missing!
);

LayrzAvatar(
  avatar: incompleteAvatar,
  nameText: 'Bob Brown',
  // Displays initials "BB" because url is null
)

Accessibility

  • Avatars are static display elements with no interaction affordances.
  • Initials text is painted directly and is accessible to screen readers if wrapped in semantic containers (e.g., a Semantics widget).
  • Icons are rendered as icon glyphs without semantic labeling (intentional, to avoid noise in screen readers for decorative avatars).

Notes

  • Static display only: No onTap, onLongPress, onSecondaryTap. Wrap with GestureDetector if needed.
  • Avatar model source: The Avatar type comes from package:layrz_sdk/layrz_sdk.dart. See the SDK documentation for the full Avatar model structure.
  • Image rendering: Images are processed by LayrzImage, which handles multiple formats and caching transparently.
  • No interaction states: Unlike LayrzButton or LayrzChip, there is no hover, press, or focus state. The component is purely presentational.

See Also

Clone this wiki locally