Repository: mui/material-ui (TypeScript)
Date: 2022-08-19 16:17:02+00:00
Task type: Feature

Issue:
AvatarGroup and Avatar use unstructured markup
### Duplicates

- [X] I have searched the existing issues

### Latest version

- [X] I have tested the latest version

### Current behavior 😯

Currently, `AvatarGroup` and `Avatar` generate `<div>`s for markup, which is not semantic/structured.

```html
<div class="MuiAvatarGroup-root css-1qy80yj-MuiAvatarGroup-root">
  <div class="MuiAvatar-root MuiAvatar-circular MuiAvatarGroup-avatar css-1ltupah-MuiAvatar-root">
    <img alt="" src="https://example.com/example.png" class="MuiAvatar-img css-1pqm26d-MuiAvatar-img">
  </div>
</div>
```

### Expected behavior 🤔

Using a list would better structure the list and its members for screen reader users:

```html
<ul class="MuiAvatarGroup-root css-1qy80yj-MuiAvatarGroup-root">
  <li class="MuiAvatar-root MuiAvatar-circular MuiAvatarGroup-avatar css-1ltupah-MuiAvatar-root">
    <img alt="" src="https://example.com/example.png" class="MuiAvatar-img css-1pqm26d-MuiAvatar-img">
  </li>
</ul>
```

### Steps to reproduce 🕹

```js
import { Avatar, AvatarGroup, } from '@mui/material';

<AvatarGroup total={totalCount}>
  {membersSample.map((member, index) => (
    <Avatar key={index} user={member} />
  ))}
</AvatarGroup>
```

### Context 🔦

This was flagged during an accessibility review of our application. Other MUI components, such as `Typography` let you override the HTML component (i.e. `component="h2"`), but AvatarGroup does not.

It would be good to (a) use `<ul>` and `<li>` as the defaults and (b) allow overriding of the component when needed.

### Your environment 🌎

<details>
  <summary><code>npx @mui/envinfo</code></summary>

```
  System:
    OS: macOS 12.5.1
  Binaries:
    Node: 18.7.0 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 8.15.0 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 104.0.5112.101
    Edge: Not Found
    Firefox: 101.0
    Safari: 15.6.1
  npmPackages:
    @emotion/react: ^11.9.3 => 11.9.3 
    @emotion/styled: ^11.9.3 => 11.9.3 
    @mui/base:  5.0.0-alpha.91 
    @mui/icons-material: ^5.8.4 => 5.8.4 
    @mui/lab: ^5.0.0-alpha.92 => 5.0.0-alpha.92 
    @mui/material: ^5.9.2 => 5.9.2 
    @mui/private-theming:  5.9.1 
    @mui/styled-engine:  5.8.7 
    @mui/system:  5.9.2 
    @mui/types:  7.1.5 
    @mui/utils:  5.9.1 
    @mui/x-data-grid: ^5.7.0 => 5.7.0 
    @types/react:  17.0.40 
    react: ^17.0.2 => 17.0.2 
    react-dom: ^17.0.2 => 17.0.2 
    typescript:  4.7.4 
```
</details>



Issue discussion:

Solution patch:
diff --git a/docs/pages/material-ui/api/avatar-group.json b/docs/pages/material-ui/api/avatar-group.json
--- a/docs/pages/material-ui/api/avatar-group.json
+++ b/docs/pages/material-ui/api/avatar-group.json
@@ -2,6 +2,7 @@
   "props": {
     "children": { "type": { "name": "node" } },
     "classes": { "type": { "name": "object" } },
+    "component": { "type": { "name": "elementType" } },
     "componentsProps": {
       "type": { "name": "shape", "description": "{ additionalAvatar?: object }" },
       "default": "{}"
diff --git a/docs/translations/api-docs/avatar-group/avatar-group.json b/docs/translations/api-docs/avatar-group/avatar-group.json
--- a/docs/translations/api-docs/avatar-group/avatar-group.json
+++ b/docs/translations/api-docs/avatar-group/avatar-group.json
@@ -3,6 +3,7 @@
   "propDescriptions": {
     "children": "The avatars to stack.",
     "classes": "Override or extend the styles applied to the component. See <a href=\"#css\">CSS API</a> below for more details.",
+    "component": "The component used for the root node. Either a string to use a HTML element or a component.",
     "componentsProps": "The props used for each slot inside the AvatarGroup.",
     "max": "Max avatars to show before +x.",
     "spacing": "Spacing between avatars.",
diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts b/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts
--- a/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts
+++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts
@@ -17,6 +17,11 @@ export interface AvatarGroupProps extends StandardProps<React.HTMLAttributes<HTM
    * Override or extend the styles applied to the component.
    */
   classes?: Partial<AvatarGroupClasses>;
+  /**
+   * The component used for the root node.
+   * Either a string to use a HTML element or a component.
+   */
+  component?: React.ElementType;
   /**
    * The props used for each slot inside the AvatarGroup.
    * @default {}
diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.js b/packages/mui-material/src/AvatarGroup/AvatarGroup.js
--- a/packages/mui-material/src/AvatarGroup/AvatarGroup.js
+++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.js
@@ -67,6 +67,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) {
   const {
     children: childrenProp,
     className,
+    component = 'div',
     componentsProps = {},
     max = 5,
     spacing = 'medium',
@@ -80,6 +81,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) {
     ...props,
     max,
     spacing,
+    component,
     variant,
   };
 
@@ -115,6 +117,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) {
 
   return (
     <AvatarGroupRoot
+      as={component}
       ownerState={ownerState}
       className={clsx(classes.root, className)}
       ref={ref}
@@ -167,6 +170,11 @@ AvatarGroup.propTypes /* remove-proptypes */ = {
    * @ignore
    */
   className: PropTypes.string,
+  /**
+   * The component used for the root node.
+   * Either a string to use a HTML element or a component.
+   */
+  component: PropTypes.elementType,
   /**
    * The props used for each slot inside the AvatarGroup.
    * @default {}
diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx b/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx
new file mode 100644
--- /dev/null
+++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx
@@ -0,0 +1,10 @@
+import * as React from 'react';
+import AvatarGroup from '@mui/material/AvatarGroup';
+
+<AvatarGroup component="ul" />;
+<AvatarGroup variant="circular" />;
+<AvatarGroup variant="rounded" />;
+<AvatarGroup variant="square" />;
+
+// @ts-expect-error
+<AvatarGroup variant="unknown" />;


Test patch:
diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js b/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js
--- a/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js
+++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js
@@ -18,7 +18,7 @@ describe('<AvatarGroup />', () => {
       muiName: 'MuiAvatarGroup',
       refInstanceof: window.HTMLDivElement,
       testVariantProps: { max: 10, spacing: 'small', variant: 'square' },
-      skip: ['componentProp', 'componentsProp'],
+      skip: ['componentsProp'],
     }),
   );