Avatar Group

Container that displays overlapping avatars with an optional "+N" overflow pill when the count exceeds the visible maximum.

Default maximum

The default max of five leaves all three avatars visible.

? ? ?

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar-group/ui-avatar-group.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar/ui-avatar.html"
>

<ui-avatar-group
  label="People"
>
  <ui-avatar
    name="Maya Chen"
    fallback="MC"
  > </ui-avatar>
  <ui-avatar
    name="Noah Williams"
    fallback="NW"
  > </ui-avatar>
  <ui-avatar
    name="Ari Kim"
    fallback="AK"
  > </ui-avatar>
</ui-avatar-group>
<script setup>
  import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";
</script>

<template>
  <UiAvatarGroup
    label="People"
  >
    <UiAvatar
      name="Maya Chen"
      fallback="MC"
    > </UiAvatar>
    <UiAvatar
      name="Noah Williams"
      fallback="NW"
    > </UiAvatar>
    <UiAvatar
      name="Ari Kim"
      fallback="AK"
    > </UiAvatar>
  </UiAvatarGroup>
</template>
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

export default function Example() {
  return <UiAvatarGroup
    label="People"
  >
    <UiAvatar
      name="Maya Chen"
      fallback="MC"
    > </UiAvatar>
    <UiAvatar
      name="Noah Williams"
      fallback="NW"
    > </UiAvatar>
    <UiAvatar
      name="Ari Kim"
      fallback="AK"
    > </UiAvatar>
  </UiAvatarGroup>;
}
/** @jsxImportSource preact */
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

export default function Example() {
  return <UiAvatarGroup
    label="People"
  >
    <UiAvatar
      name="Maya Chen"
      fallback="MC"
    > </UiAvatar>
    <UiAvatar
      name="Noah Williams"
      fallback="NW"
    > </UiAvatar>
    <UiAvatar
      name="Ari Kim"
      fallback="AK"
    > </UiAvatar>
  </UiAvatarGroup>;
}
<script>
  import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";
</script>

<UiAvatarGroup
  label="People"
>
  <UiAvatar
    name="Maya Chen"
    fallback="MC"
  > </UiAvatar>
  <UiAvatar
    name="Noah Williams"
    fallback="NW"
  > </UiAvatar>
  <UiAvatar
    name="Ari Kim"
    fallback="AK"
  > </UiAvatar>
</UiAvatarGroup>
import { Component } from "@angular/core";
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiAvatarGroup, UiAvatar],
  template: `
    <div
      ui-avatar-group
      [label]="'People'"
    >
      <span
        ui-avatar
        [name]="'Maya Chen'"
        [fallback]="'MC'"
      > </span>
      <span
        ui-avatar
        [name]="'Noah Williams'"
        [fallback]="'NW'"
      > </span>
      <span
        ui-avatar
        [name]="'Ari Kim'"
        [fallback]="'AK'"
      > </span>
    </div>
  `,
})
export default class Example {}

max="2"

Max limits the visible avatars and replaces the remainder with an overflow count.

? ? ? ?

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar-group/ui-avatar-group.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar/ui-avatar.html"
>

<ui-avatar-group
  max="2"
  label="Reviewers"
>
  <ui-avatar
    name="Maya Chen"
    fallback="MC"
  > </ui-avatar>
  <ui-avatar
    name="Noah Williams"
    fallback="NW"
  > </ui-avatar>
  <ui-avatar
    name="Ari Kim"
    fallback="AK"
  > </ui-avatar>
  <ui-avatar
    name="Sam Rivera"
    fallback="SR"
  > </ui-avatar>
</ui-avatar-group>
<script setup>
  import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";
</script>

<template>
  <UiAvatarGroup
    :max="2"
    label="Reviewers"
  >
    <UiAvatar
      name="Maya Chen"
      fallback="MC"
    > </UiAvatar>
    <UiAvatar
      name="Noah Williams"
      fallback="NW"
    > </UiAvatar>
    <UiAvatar
      name="Ari Kim"
      fallback="AK"
    > </UiAvatar>
    <UiAvatar
      name="Sam Rivera"
      fallback="SR"
    > </UiAvatar>
  </UiAvatarGroup>
</template>
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

export default function Example() {
  return <UiAvatarGroup
    max={2}
    label="Reviewers"
  >
    <UiAvatar
      name="Maya Chen"
      fallback="MC"
    > </UiAvatar>
    <UiAvatar
      name="Noah Williams"
      fallback="NW"
    > </UiAvatar>
    <UiAvatar
      name="Ari Kim"
      fallback="AK"
    > </UiAvatar>
    <UiAvatar
      name="Sam Rivera"
      fallback="SR"
    > </UiAvatar>
  </UiAvatarGroup>;
}
/** @jsxImportSource preact */
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

export default function Example() {
  return <UiAvatarGroup
    max={2}
    label="Reviewers"
  >
    <UiAvatar
      name="Maya Chen"
      fallback="MC"
    > </UiAvatar>
    <UiAvatar
      name="Noah Williams"
      fallback="NW"
    > </UiAvatar>
    <UiAvatar
      name="Ari Kim"
      fallback="AK"
    > </UiAvatar>
    <UiAvatar
      name="Sam Rivera"
      fallback="SR"
    > </UiAvatar>
  </UiAvatarGroup>;
}
<script>
  import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";
</script>

<UiAvatarGroup
  max={2}
  label="Reviewers"
>
  <UiAvatar
    name="Maya Chen"
    fallback="MC"
  > </UiAvatar>
  <UiAvatar
    name="Noah Williams"
    fallback="NW"
  > </UiAvatar>
  <UiAvatar
    name="Ari Kim"
    fallback="AK"
  > </UiAvatar>
  <UiAvatar
    name="Sam Rivera"
    fallback="SR"
  > </UiAvatar>
</UiAvatarGroup>
import { Component } from "@angular/core";
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiAvatarGroup, UiAvatar],
  template: `
    <div
      ui-avatar-group
      [max]="2"
      [label]="'Reviewers'"
    >
      <span
        ui-avatar
        [name]="'Maya Chen'"
        [fallback]="'MC'"
      > </span>
      <span
        ui-avatar
        [name]="'Noah Williams'"
        [fallback]="'NW'"
      > </span>
      <span
        ui-avatar
        [name]="'Ari Kim'"
        [fallback]="'AK'"
      > </span>
      <span
        ui-avatar
        [name]="'Sam Rivera'"
        [fallback]="'SR'"
      > </span>
    </div>
  `,
})
export default class Example {}

Truncated people

Total counts people whose avatars are not authored; overflow-label names the remaining count for assistive technology.

? ?

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar-group/ui-avatar-group.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar/ui-avatar.html"
>

<ui-avatar-group
  label="Contributors"
  max="2"
  total="7"
  overflow-label="{count} other contributors"
>
  <ui-avatar
    name="Ada Lovelace"
  ></ui-avatar>
  <ui-avatar
    name="Grace Hopper"
  ></ui-avatar>
</ui-avatar-group>
<script setup>
  import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";
</script>

<template>
  <UiAvatarGroup
    label="Contributors"
    :max="2"
    :total="7"
    overflow-label="&#123;count} other contributors"
  >
    <UiAvatar
      name="Ada Lovelace"
    />
    <UiAvatar
      name="Grace Hopper"
    />
  </UiAvatarGroup>
</template>
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

export default function Example() {
  return <UiAvatarGroup
    label="Contributors"
    max={2}
    total={7}
    overflowLabel="{count} other contributors"
  >
    <UiAvatar
      name="Ada Lovelace"
    />
    <UiAvatar
      name="Grace Hopper"
    />
  </UiAvatarGroup>;
}
/** @jsxImportSource preact */
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

export default function Example() {
  return <UiAvatarGroup
    label="Contributors"
    max={2}
    total={7}
    overflowLabel="{count} other contributors"
  >
    <UiAvatar
      name="Ada Lovelace"
    />
    <UiAvatar
      name="Grace Hopper"
    />
  </UiAvatarGroup>;
}
<script>
  import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";
</script>

<UiAvatarGroup
  label="Contributors"
  max={2}
  total={7}
  overflowLabel="&#123;count} other contributors"
>
  <UiAvatar
    name="Ada Lovelace"
  />
  <UiAvatar
    name="Grace Hopper"
  />
</UiAvatarGroup>
import { Component } from "@angular/core";
import { UiAvatar, UiAvatarGroup } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiAvatarGroup, UiAvatar],
  template: `
    <div
      ui-avatar-group
      [label]="'Contributors'"
      [max]="2"
      [total]="7"
      [overflowLabel]="'{count} other contributors'"
    >
      <span
        ui-avatar
        [name]="'Ada Lovelace'"
      ></span>
      <span
        ui-avatar
        [name]="'Grace Hopper'"
      ></span>
    </div>
  `,
})
export default class Example {}

size

Size matches the avatars inside: the +N badge and the overlap follow it. xs suits a group inside a line of small text, such as the people listed under a title.

? ? ?
? ? ?
? ? ?

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-cluster/ui-cluster.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar-group/ui-avatar-group.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-avatar/ui-avatar.html"
>

<ui-cluster
  gap="m"
  align="center"
>
  <ui-avatar-group
    size="xs"
    max="2"
    label="Looked after by"
  >
    <ui-avatar
      name="Ada Lovelace"
      size="xs"
    ></ui-avatar>
    <ui-avatar
      name="Grace Hopper"
      size="xs"
    ></ui-avatar>
    <ui-avatar
      name="Alan Turing"
      size="xs"
    ></ui-avatar>
  </ui-avatar-group>
  <ui-avatar-group
    size="sm"
    max="2"
    label="Reviewers"
  >
    <ui-avatar
      name="Ada Lovelace"
      size="sm"
    ></ui-avatar>
    <ui-avatar
      name="Grace Hopper"
      size="sm"
    ></ui-avatar>
    <ui-avatar
      name="Alan Turing"
      size="sm"
    ></ui-avatar>
  </ui-avatar-group>
  <ui-avatar-group
    max="2"
    label="People"
  >
    <ui-avatar
      name="Ada Lovelace"
    ></ui-avatar>
    <ui-avatar
      name="Grace Hopper"
    ></ui-avatar>
    <ui-avatar
      name="Alan Turing"
    ></ui-avatar>
  </ui-avatar-group>
</ui-cluster>
<script setup>
  import { UiAvatar, UiAvatarGroup, UiCluster } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="m"
    align="center"
  >
    <UiAvatarGroup
      size="xs"
      :max="2"
      label="Looked after by"
    >
      <UiAvatar
        name="Ada Lovelace"
        size="xs"
      />
      <UiAvatar
        name="Grace Hopper"
        size="xs"
      />
      <UiAvatar
        name="Alan Turing"
        size="xs"
      />
    </UiAvatarGroup>
    <UiAvatarGroup
      size="sm"
      :max="2"
      label="Reviewers"
    >
      <UiAvatar
        name="Ada Lovelace"
        size="sm"
      />
      <UiAvatar
        name="Grace Hopper"
        size="sm"
      />
      <UiAvatar
        name="Alan Turing"
        size="sm"
      />
    </UiAvatarGroup>
    <UiAvatarGroup
      :max="2"
      label="People"
    >
      <UiAvatar
        name="Ada Lovelace"
      />
      <UiAvatar
        name="Grace Hopper"
      />
      <UiAvatar
        name="Alan Turing"
      />
    </UiAvatarGroup>
  </UiCluster>
</template>
import { UiAvatar, UiAvatarGroup, UiCluster } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="m"
    align="center"
  >
    <UiAvatarGroup
      size="xs"
      max={2}
      label="Looked after by"
    >
      <UiAvatar
        name="Ada Lovelace"
        size="xs"
      />
      <UiAvatar
        name="Grace Hopper"
        size="xs"
      />
      <UiAvatar
        name="Alan Turing"
        size="xs"
      />
    </UiAvatarGroup>
    <UiAvatarGroup
      size="sm"
      max={2}
      label="Reviewers"
    >
      <UiAvatar
        name="Ada Lovelace"
        size="sm"
      />
      <UiAvatar
        name="Grace Hopper"
        size="sm"
      />
      <UiAvatar
        name="Alan Turing"
        size="sm"
      />
    </UiAvatarGroup>
    <UiAvatarGroup
      max={2}
      label="People"
    >
      <UiAvatar
        name="Ada Lovelace"
      />
      <UiAvatar
        name="Grace Hopper"
      />
      <UiAvatar
        name="Alan Turing"
      />
    </UiAvatarGroup>
  </UiCluster>;
}
/** @jsxImportSource preact */
import { UiAvatar, UiAvatarGroup, UiCluster } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="m"
    align="center"
  >
    <UiAvatarGroup
      size="xs"
      max={2}
      label="Looked after by"
    >
      <UiAvatar
        name="Ada Lovelace"
        size="xs"
      />
      <UiAvatar
        name="Grace Hopper"
        size="xs"
      />
      <UiAvatar
        name="Alan Turing"
        size="xs"
      />
    </UiAvatarGroup>
    <UiAvatarGroup
      size="sm"
      max={2}
      label="Reviewers"
    >
      <UiAvatar
        name="Ada Lovelace"
        size="sm"
      />
      <UiAvatar
        name="Grace Hopper"
        size="sm"
      />
      <UiAvatar
        name="Alan Turing"
        size="sm"
      />
    </UiAvatarGroup>
    <UiAvatarGroup
      max={2}
      label="People"
    >
      <UiAvatar
        name="Ada Lovelace"
      />
      <UiAvatar
        name="Grace Hopper"
      />
      <UiAvatar
        name="Alan Turing"
      />
    </UiAvatarGroup>
  </UiCluster>;
}
<script>
  import { UiAvatar, UiAvatarGroup, UiCluster } from "@threadlabs/looma";
</script>

<UiCluster
  gap="m"
  align="center"
>
  <UiAvatarGroup
    size="xs"
    max={2}
    label="Looked after by"
  >
    <UiAvatar
      name="Ada Lovelace"
      size="xs"
    />
    <UiAvatar
      name="Grace Hopper"
      size="xs"
    />
    <UiAvatar
      name="Alan Turing"
      size="xs"
    />
  </UiAvatarGroup>
  <UiAvatarGroup
    size="sm"
    max={2}
    label="Reviewers"
  >
    <UiAvatar
      name="Ada Lovelace"
      size="sm"
    />
    <UiAvatar
      name="Grace Hopper"
      size="sm"
    />
    <UiAvatar
      name="Alan Turing"
      size="sm"
    />
  </UiAvatarGroup>
  <UiAvatarGroup
    max={2}
    label="People"
  >
    <UiAvatar
      name="Ada Lovelace"
    />
    <UiAvatar
      name="Grace Hopper"
    />
    <UiAvatar
      name="Alan Turing"
    />
  </UiAvatarGroup>
</UiCluster>
import { Component } from "@angular/core";
import { UiAvatar, UiAvatarGroup, UiCluster } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiAvatarGroup, UiAvatar],
  template: `
    <div
      ui-cluster
      [gap]="'m'"
      [align]="'center'"
    >
      <div
        ui-avatar-group
        [size]="'xs'"
        [max]="2"
        [label]="'Looked after by'"
      >
        <span
          ui-avatar
          [name]="'Ada Lovelace'"
          [size]="'xs'"
        ></span>
        <span
          ui-avatar
          [name]="'Grace Hopper'"
          [size]="'xs'"
        ></span>
        <span
          ui-avatar
          [name]="'Alan Turing'"
          [size]="'xs'"
        ></span>
      </div>
      <div
        ui-avatar-group
        [size]="'sm'"
        [max]="2"
        [label]="'Reviewers'"
      >
        <span
          ui-avatar
          [name]="'Ada Lovelace'"
          [size]="'sm'"
        ></span>
        <span
          ui-avatar
          [name]="'Grace Hopper'"
          [size]="'sm'"
        ></span>
        <span
          ui-avatar
          [name]="'Alan Turing'"
          [size]="'sm'"
        ></span>
      </div>
      <div
        ui-avatar-group
        [max]="2"
        [label]="'People'"
      >
        <span
          ui-avatar
          [name]="'Ada Lovelace'"
        ></span>
        <span
          ui-avatar
          [name]="'Grace Hopper'"
        ></span>
        <span
          ui-avatar
          [name]="'Alan Turing'"
        ></span>
      </div>
    </div>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: div

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
labelThe group's accessible name, announced for the set of avatars as a whole. Name who they are rather than repeating the default.labelstringPeople—
maxHow many avatars to show. The rest are hidden and counted in a +N badge after the last visible one. Fractions round down, and 0 hides every avatar behind the badge.maxnumber5—
overflow-labelAccessible label for the overflow badge. Replace {count} with the number of people beyond the visible avatars.overflowLabelstring{count} more—
sizeThe size of the avatars inside, matched by the +N badge and the overlap. Give each Avatar the same size. xs suits a group inside a line of small text, such as the people listed under a title.sizekeywordmdxs, sm, md
totalThe true number of people when only some avatars are authored. The overflow badge counts the people beyond the visible avatars; it never counts fewer than the authored avatars.totalinteger——

Framework props

NameTypeDefaultAllowed values
labelstringPeople—
maxnumber5—
overflowLabelstring{count} more—
size"xs" | "sm" | "md"mdxs, sm, md
totalnumber——

Events

No events.

Slots

NamePurpose
defaultDefault child content.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

TokenDeclared valuesFallback
--ui-avatar-group-edge-ring—0 0 0 0 transparent
--ui-avatar-group-overlap-shadow-1px 0 0 0 rgb(0 0 0 / 0.22) | 1px 0 0 0 rgb(0 0 0 / 0.22)—

Shared tokens

TokenFallback
--ui-border-strong—
--ui-border-width—
--ui-font-size-md—
--ui-font-size-xs—
--ui-radius-round—
--ui-surface-elevated—
--ui-text-primary—