← All proposals

Avatar Label

The PDS v2 AvatarLabel (src/components/identity/AvatarLabel, branch v2.x) with every Avatar replaced by the Agent Avatar proposal.

Net-new componentOpen in Storybook

proposals/AvatarLabel/HANDOFF.md84 lines · View on GitHub

Handoff: AvatarLabel (agent)

What and why

Activity logs, threads and lists show who did something. For an agent, that is the Agent Avatar next to the agent's name. The PDS AvatarLabel pairs a human Avatar with a label, so this is the same component with the Agent Avatar in place of every Avatar. It also adds an optional attribution ("Zappy on behalf of alex@example.com") and a hasAvatar switch.

The port is a diff against src/components/identity/AvatarLabel on v2.x.

  • Figma / Jira: none. Source was the PDS Avatar Label and the design brief for attribution.
  • Context: context.md

Exploration and decisions

  • Agent Avatar replaces Avatar everywhere. The human avatar is no longer reachable from this component; for people, use the PDS Avatar Label.
  • avatarProps is required (it carries the avatar's label), because the visible label is the agent's name and does not say it is an agent.
  • attribution is one ReactNode holding the whole phrase, not separate "on behalf of" and email props. The connecting words are translatable and word order differs by language, so no text is hardcoded. It renders after the name in the secondary color and truncates before the name does. The screen builds the phrase from the triggering user and passes nothing for scheduled or autonomous runs.
  • hasAvatar (default true): false shows only the name and attribution, for when the avatar is already shown nearby. The avatar's label still renders as screen-reader text.
  • A truncated string attribution keeps its full text in a title.
  • The class stays pds-avatar-label. Open below.

API

Prop Type Default Purpose
ariaLabel string none Accessible name for the whole component as a link, if the label is not enough.
attribution ReactNode none Whole phrase saying who the agent acts for.
avatarProps Omit<AgentAvatarProps, 'ariaLabel' | 'linkContent' | 'size'> required Agent Avatar props. label is required. size follows size.
className string none Additional class names.
hasAvatar boolean true Show the avatar.
label ReactNode required Text next to the avatar.
linkContent ReactNode none Makes the whole component a link.
size 'xs' | 's' | 'm' 's' Avatar size and text size.

Variants and states: three sizes; with and without attribution; with and without the avatar; as a link (hover and focus-visible); truncated attribution.

Tokens used

  • --pds-border-radius-container
  • --pds-border-width-outline
  • --pds-color-foreground-default
  • --pds-color-foreground-default-secondary
  • --pds-color-interactive-focus
  • --pds-color-interactive-link-default
  • --pds-spacing-2xs
  • --pds-spacing-xs
  • --pds-typography-ff-default
  • --pds-typography-fw-medium
  • --pds-typography-fw-regular
  • --pds-typography-size-s
  • --pds-typography-size-xs

Impact

impact.md finds nothing that reaches existing PDS components. The additions (pds-avatar-label--has-attribution, pds-avatar-label__attribution) only apply where those classes are used. The class name pds-avatar-label is shared with the published package, so this CSS overrides the package's by class name. Nothing else here depends on this proposal. It depends on AgentAvatar.

Reused vs net-new

  • Reused: the v2 AvatarLabel structure, sizes and link behavior; the Agent Avatar proposal.
  • Net-new: the attribution and hasAvatar props, and the two classes above. See custom.md.

Accessibility

  • The avatar's label always reaches screen readers, even with hasAvatar={false} (as visually-hidden text, out of flow).
  • A plain space is rendered between the name and the attribution so they are not read as one word.
  • As a link, the whole component is the link; focus-visible uses --pds-color-interactive-focus.
  • The a11y panel has not been run on these stories. Run it in light and dark before the port.

Decisions and open questions

  • Rename the class (for example pds-agent-avatar-label), since the published package already ships CSS for pds-avatar-label?
  • Should the email in the attribution be a separate element so it can be copied or linked?
  • attribution is a working name; alternatives were onBehalfOf and actingFor.

Port notes

  • Goes in src/components/identity/AvatarLabel (or a new AgentAvatarLabel next to it, depending on the class-name call above). Use npm run generate:component.
  • Swap the local mergeClasses for the real one. Port AgentAvatar first.

Preview

npm run storybook, then Component Proposals/Identity/Avatar Label.

Figma: https://www.figma.com/design/AMGWJbraJoi2PKWnxo29Ah/PDS-Proposals?node-id=374-43, page Avatar Label (6 stories, light only; captures of Storybook with library icons swapped in, sent 2026-10-20).