{
  "componentId": "avatar-group",
  "componentName": "Avatar Group",
  "lastReviewed": "2026-05-05",
  "keyboardWalk": [
    {
      "keys": "Tab (static group, no overflow popover)",
      "expected": "Static avatar groups are not in the tab order — the group is decorative-or-informational and individual avatars are not focusable. Tab moves through the surrounding host controls (sidebar, header, list)."
    },
    {
      "keys": "Tab (interactive group, overflow indicator opens popover)",
      "expected": "Tab lands on the overflow indicator (a `<button>`) as a single tab stop. The avatar slots themselves remain non- focusable unless individually wrapped in their own buttons / links by the host context (member-link composition)."
    },
    {
      "keys": "Enter, Space (overflow indicator focused)",
      "expected": "Activates the indicator. Popover opens; focus moves into the popover (first focusable element or the popover container with `tabindex=\"-1\"`). `aria-expanded` flips to true."
    },
    {
      "keys": "Escape (popover open)",
      "expected": "Closes the popover. Focus returns to the overflow indicator. `aria-expanded` flips back to false."
    },
    {
      "keys": "Tab (popover open, focus inside popover)",
      "expected": "Moves through focusable elements inside the popover (member rows, dismiss button). When the popover is a `role=\"listbox\"` member-list, arrow keys navigate instead of Tab."
    }
  ],
  "announcements": [
    {
      "trigger": "SR encounters the avatar group container",
      "expected": "SR announces the group role and accessible name first (\"group, Document collaborators, 8 members\"). Reading continues with the visible avatars in DOM order (\"Alex Black, Jamie Lee, Sam Reyes\") and ends with the overflow indicator (\"button, 5 more members, collapsed\")."
    },
    {
      "trigger": "User activates the overflow indicator",
      "expected": "SR announces the popover open (\"dialog\" or \"list, 5 items\") and reads the first focusable element. The indicator's `aria-expanded` flip is announced."
    },
    {
      "trigger": "Popover dismisses",
      "expected": "SR announces focus return to the indicator. The `aria-expanded=\"false\"` state is reflected in the next announcement."
    }
  ],
  "axeRules": [
    "aria-allowed-attr",
    "aria-required-attr",
    "aria-valid-attr-value",
    "button-name",
    "color-contrast"
  ],
  "_about": "Per-component a11y-acceptance data shaped for direct ingestion into Playwright + @axe-core/playwright or Jest + jest-axe.\n\nSuggested wiring:\n- axeRules → pass to AxeBuilder.options({ runOnly: { type: \"rule\", values: axeRules } }) so the run targets only the rules the canon has pinned for this component (other rules can run in your global pass).\n- keyboardWalk → iterate the entries; each `keys` is a human-readable sequence (e.g. \"Tab → Tab → Esc\"). Translate to page.keyboard.press calls and assert `expected` against the result (focused element, aria-state, visible text, etc.).\n- announcements → assert text content of any aria-live region or capture the accessibility tree at the trigger moment and match against `expected`.\n\nEmpty sub-arrays mean the canon does not yet pin behaviour for that axis on this component, not that none is required."
}