Skip to content
Gx
GitHub

Avatar

A user image with a fallback.

<avatar.Avatar fallback="NA" src={""} />

Installation

Run the command in the app module.

Terminal
gx add avatar

The command writes these files.

File Path in the app
Avatar.gx ui/avatar/Avatar.gx
Avatar.fixtures.go ui/avatar/Avatar.fixtures.go
styles.go ui/avatar/styles.go
AvatarBadge.gx ui/avatar/AvatarBadge.gx
AvatarBadge.fixtures.go ui/avatar/AvatarBadge.fixtures.go
AvatarGroup.gx ui/avatar/AvatarGroup.gx
AvatarGroup.fixtures.go ui/avatar/AvatarGroup.fixtures.go
AvatarGroupCount.gx ui/avatar/AvatarGroupCount.gx
AvatarGroupCount.fixtures.go ui/avatar/AvatarGroupCount.fixtures.go

Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.

ui/avatar/Avatar.gx
package avatar

props {
  // Src is the URL of the image. An empty value renders the fallback.
  Src      gx.URL
  // Alt is the alt text of the image.
  Alt      string = ""
  // Fallback is the text shown when Src is empty, for example the initials of the user.
  Fallback string = ""
  // Size sets the diameter: Sm, Md or Lg.
  Size     Size = Md
  // Badge is an AvatarBadge shown at the bottom right corner. A nil value renders no badge.
  Badge    gx.Node = nil
  // Class adds classes to the root element.
  Class    string = ""
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<span data-slot="avatar" data-size={p.size()} class={gx.Cx("group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6", p.Class)} {...p.Attrs}>
  if p.Src != "" {
    <img data-slot="avatar-image" src={p.Src} alt={p.Alt} class="aspect-square size-full rounded-full object-cover" />
  } else if p.Fallback != "" {
    <span data-slot="avatar-fallback" class="flex size-full items-center justify-center rounded-full bg-muted text-sm text-foreground group-data-[size=sm]/avatar:text-xs">{p.Fallback}</span>
  }
  if p.Badge != nil {
    {p.Badge}
  }
</span>
ui/avatar/Avatar.fixtures.go
package avatar

import "github.com/alternayte/gx"

var AvatarFixtures = gx.Fixtures[AvatarProps]{
	"Fallback": {Fallback: "NA"},
	"Small":    {Fallback: "NA", Size: Sm},
	"Large":    {Fallback: "NA", Size: Lg},
	"Badge":    {Fallback: "NA", Badge: AvatarBadge(AvatarBadgeProps{})},
	"LargeBadge": {Fallback: "NA", Size: Lg, Badge: AvatarBadge(AvatarBadgeProps{
		Class: "bg-green-600 dark:bg-green-800",
	})},
}
ui/avatar/styles.go
package avatar

// Size is the diameter of an avatar.
type Size string

// The sizes of avatar.Avatar.
const (
	Sm Size = "sm"
	Md Size = "default"
	Lg Size = "lg"
)

// size returns the data-size value; a zero value is Md. The size classes
// of the avatar, its fallback and its badge follow this attribute.
func (p AvatarProps) size() string {
	if p.Size == "" {
		return string(Md)
	}
	return string(p.Size)
}
ui/avatar/AvatarBadge.gx
package avatar

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the badge: an icon. A nil value renders a dot.
  Children gx.Node = nil
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<span data-slot="avatar-badge" class={gx.Cx("absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2 group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", p.Class)} {...p.Attrs}>{p.Children}</span>
ui/avatar/AvatarBadge.fixtures.go
package avatar

import "github.com/alternayte/gx"

var AvatarBadgeFixtures = gx.Fixtures[AvatarBadgeProps]{"Default": {}}

// AvatarBadgeWrap renders the badge on an avatar, as a page uses it.
func AvatarBadgeWrap(n gx.Node) gx.Node {
	return Avatar(AvatarProps{Fallback: "NA", Badge: n})
}
ui/avatar/AvatarGroup.gx
package avatar

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the group: the avatars and an optional AvatarGroupCount.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<div data-slot="avatar-group" class={gx.Cx("group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", p.Class)} {...p.Attrs}>{p.Children}</div>
ui/avatar/AvatarGroup.fixtures.go
package avatar

import "github.com/alternayte/gx"

var AvatarGroupFixtures = gx.Fixtures[AvatarGroupProps]{
	"Three": {Children: gx.Frag(
		Avatar(AvatarProps{Fallback: "NA"}),
		Avatar(AvatarProps{Fallback: "AL"}),
		Avatar(AvatarProps{Fallback: "GH"}),
		AvatarGroupCount(AvatarGroupCountProps{Children: gx.Text("+3")}),
	)},
	"Small": {Children: gx.Frag(
		Avatar(AvatarProps{Fallback: "NA", Size: Sm}),
		Avatar(AvatarProps{Fallback: "AL", Size: Sm}),
		AvatarGroupCount(AvatarGroupCountProps{Children: gx.Text("+2")}),
	)},
}
ui/avatar/AvatarGroupCount.gx
package avatar

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the count, for example +3 or an icon.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<div data-slot="avatar-group-count" class={gx.Cx("relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", p.Class)} {...p.Attrs}>{p.Children}</div>
ui/avatar/AvatarGroupCount.fixtures.go
package avatar

import "github.com/alternayte/gx"

var AvatarGroupCountFixtures = gx.Fixtures[AvatarGroupCountProps]{"Count": {Children: gx.Text("+3")}}

The theme must define these tokens: --muted, --foreground, --primary, --primary-foreground, --background.

Usage

<avatar.Avatar src={gx.URL(user.Image)} alt={user.Name} fallback="NA" />
<avatar.Avatar fallback="NA" size={avatar.Lg} badge={<avatar.AvatarBadge />} />

<avatar.AvatarGroup>
  <avatar.Avatar fallback="NA" />
  <avatar.Avatar fallback="AL" />
  <avatar.AvatarGroupCount>+3</avatar.AvatarGroupCount>
</avatar.AvatarGroup>

The sizes are Sm, Md and Lg. The fallback, the badge and the group count follow the size of the avatar. AvatarBadge takes an icon as its child. A small avatar hides the icon.

Examples

Avatar: Fallback

<avatar.Avatar fallback="NA" src={""} />

Avatar: Small

<avatar.Avatar fallback="NA" size={avatar.Sm} src={""} />

Avatar: Large

<avatar.Avatar fallback="NA" size={avatar.Lg} src={""} />

Avatar: Badge

<avatar.Avatar fallback="NA" src={""}><:badge><avatar.AvatarBadge /></:badge></avatar.Avatar>

Avatar: Large badge

<avatar.Avatar fallback="NA" size={avatar.Lg} src={""}>
  <:badge><avatar.AvatarBadge class="bg-green-600 dark:bg-green-800" /></:badge>
</avatar.Avatar>

AvatarBadge: Default

<avatar.AvatarBadge />

AvatarGroup: Three

<avatar.AvatarGroup>
  <avatar.Avatar fallback="NA" src={""} />
  <avatar.Avatar fallback="AL" src={""} />
  <avatar.Avatar fallback="GH" src={""} />
  <avatar.AvatarGroupCount>+3</avatar.AvatarGroupCount>
</avatar.AvatarGroup>

AvatarGroup: Small

<avatar.AvatarGroup>
  <avatar.Avatar fallback="NA" size={avatar.Sm} src={""} />
  <avatar.Avatar fallback="AL" size={avatar.Sm} src={""} />
  <avatar.AvatarGroupCount>+2</avatar.AvatarGroupCount>
</avatar.AvatarGroup>

AvatarGroupCount: Count

<avatar.AvatarGroupCount>+3</avatar.AvatarGroupCount>

API reference

A tag sets a prop by its name with a lower-case first letter: Class is class.

avatar.Avatar

Prop Type Default Description
Src gx.URL Required Src is the URL of the image. An empty value renders the fallback.
Alt string "" Alt is the alt text of the image.
Fallback string "" Fallback is the text shown when Src is empty, for example the initials of the user.
Size Size Md Size sets the diameter: Sm, Md or Lg.
Badge gx.Node nil Badge is an AvatarBadge shown at the bottom right corner. A nil value renders no badge.
Class string "" Class adds classes to the root element.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

avatar.AvatarBadge

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node nil Children is the content of the badge: an icon. A nil value renders a dot.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

avatar.AvatarGroup

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the content of the group: the avatars and an optional AvatarGroupCount.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

avatar.AvatarGroupCount

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the content of the count, for example +3 or an icon.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

Do and do not

Do

  • Always set Alt when the image carries meaning.
  • Set Fallback to the initials of the user.
  • Use one size for every avatar of a group.

Don't

  • Do not build an image URL from a raw string. Use gx.URL.
  • Do not use an avatar as the only label of an action.

Keyboard

Key Action
None The component is static.