AvatarGroup is used to both display a group of user avatars and, optionally, control actions related to the users group.

also known as Pinner reps, Personas, Facepile, User Images, Identification Group, Identicons

Figma:

Responsive:

Adaptive:

Props

Component props
Name
Type
Default
accessibilityLabel
Required
string
-

Label for screen readers to announce AvatarGroup.

See the Accessibility guidelines for details on proper usage.

collaborators
Required
ReadonlyArray<{
  color?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
  name: string;
  src?: string;
}>
-

The user group data. See the collaborators display variant to learn more.

accessibilityControls
string
-

Specify the id of an associated element (or elements) whose contents or visibility are controlled by a component so that screen reader users can identify the relationship between elements. Optional with button-role component.

See the Accessibility guidelines for details on proper usage.

accessibilityExpanded
boolean
-

Indicate that a component hides or exposes collapsible components and expose whether they are currently expanded or collapsed. Optional with button-role component.

See the Accessibility guidelines for details on proper usage.

accessibilityHaspopup
boolean
-

Indicate that a component controls the appearance of interactive popup elements, such as menu or dialog. Optional with button-role component.

See the Accessibility guidelines for details on proper usage.

addCollaborators
boolean
-

When supplied, it appends an add icon to the avatar pile as a call to action to the user. Not available for 'xs' size. See Best Practices for more info.

href
string
-

When supplied, wraps the component in a link, and directs users to the url when item is selected. See the role variant to learn more.

onClick
(arg1: {
  event:
    | React.MouseEvent<HTMLDivElement>
    | React.KeyboardEvent<HTMLDivElement>
    | React.MouseEvent<HTMLAnchorElement>
    | React.KeyboardEvent<HTMLAnchorElement>;
  dangerouslyDisableOnNavigation: () => void;
}) => void
-

Callback fired when the component is clicked (pressed and released) with a mouse or keyboard. See the role variant to learn more and see TapArea's onTap for more info about OnTapType.

ref
HTMLDivElement | HTMLAnchorElement
-

Forward the ref to the underlying div or anchor element. See the role variant to learn more.

role
"link" | "button"
-

Allows user interaction with the component. See the role variant to learn more.

size
"xs" | "sm" | "md" | "fit"
-

The maximum height of AvatarGroup. If size is fit, AvatarGroup will fill 100% of the parent container width. See the fixed size and responsive size variant to learn more.

Usage guidelines

When to use
  • For the general display of groups of people, companies and/or brands.
  • In cases where an affordance for adding collaborators is needed.

Best Practices

Do

Use the default alternative if no image source is available. This should be the first character of the provided name.

Don't

Use alternative graphics or icons

Do

Use AvatarGroup to represent a group of people and/or organizations.

Don't

Use AvatarGroup to represent metaphorical ideas, like multiple Boards or trends. Instead, consider an Image or the appropriate interactive component.

Accessibility

ARIA attributes

AvatarGroup requires accessibilityLabel. AvatarGroup is a group of elements that require a parent label describing both the data presented and the call to action in the case of button and link roles. As seen in the example below, the screen-reader reads: "Collaborators: Keerthi, Alberto, and 10 more. Add collaborators to this board."

If AvatarGroup is used as a control button to show/hide Popover-component, we recommend passing the following ARIA attributes to assist screen readers:

  • accessibilityControls: informs the screen reader that AvatarGroup controls the display of an anchored Popover-component. It populates aria-controls.
  • accessibilityHaspopup: informs the screen reader that there’s a Popover-component attached to AvatarGroup. It populates aria-haspopup.
  • accessibilityExpanded: informs the screen reader whether an anchored Popover-component is currently open or closed. It populates aria-expanded.
import { useEffect, useRef, useState } from 'react';
import {
  AvatarGroup,
  Box,
  Flex,
  Layer,
  Popover,
  SearchField,
  Text,
  useDangerouslyInGestaltExperiment,
} from 'gestalt';

function SearchCollaboratorsField() {
  const ref = useRef(null);

  useEffect(() => {
    if (ref.current) ref.current.focus();
  }, []);

  return (
    <SearchField
      ref={ref}
      accessibilityLabel="Search other users"
      id="searchField"
      onChange={() => {}}
      placeholder="Search by name or email"
      size="lg"
    />
  );
}

export default function Example() {
  const [open, setOpen] = useState(false);
  const anchorRef = useRef(null);
  const isInVRExperiment = useDangerouslyInGestaltExperiment({
    webExperimentName: 'web_gestalt_visualRefresh',
    mwebExperimentName: 'web_gestalt_visualRefresh',
  });

  const collaborators = [
    {
      name: 'Keerthi',
      src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg',
    },
    {
      name: 'Alberto',
      src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg',
    },
    ...new Array(10),
  ];

  const collaboratorsVR = [
    {
      name: 'Fatima',
      src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg',
    },
    {
      name: 'Ayesha',
      src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg',
    },
    ...new Array(10),
  ];

  const names = isInVRExperiment ? 'Fatima, Ayesha,' : 'Keerthi, Alberto,';

  return isInVRExperiment ? (
    <Flex height="100%" width="100%">
      <Box height="200" marginTop={6} padding={2}>
        <AvatarGroup
          ref={anchorRef}
          accessibilityExpanded={open}
          accessibilityLabel={`Collaborators: ${names} and 10 more. Add collaborators to this board.`}
          addCollaborators
          collaborators={collaboratorsVR}
          onClick={() => setOpen((value) => !value)}
          role="button"
          size="md"
        />
      </Box>
      {open && (
        <Layer>
          <Popover
            anchor={anchorRef.current}
            idealDirection="down"
            onDismiss={() => setOpen(false)}
            positionRelativeToAnchor={false}
            size={500}
          >
            <Box
              flex="grow"
              marginBottom={8}
              marginEnd={4}
              marginStart={4}
              marginTop={6}
              width={360}
            >
              <Flex direction="column" gap={{ column: 4, row: 0 }}>
                <Text align="center" color="default" weight="bold">
                  Invite collaborators
                </Text>
                <SearchCollaboratorsField />
              </Flex>
            </Box>
          </Popover>
        </Layer>
      )}
    </Flex>
  ) : (
    <Flex height="100%" width="100%">
      <Box height="200" marginTop={6} padding={2}>
        <AvatarGroup
          ref={anchorRef}
          accessibilityExpanded={open}
          accessibilityLabel={`Collaborators: ${names} and 10 more. Add collaborators to this board.`}
          addCollaborators
          collaborators={isInVRExperiment ? collaboratorsVR : collaborators}
          onClick={() => setOpen((value) => !value)}
          role="button"
          size="md"
        />
      </Box>
      {open && (
        <Layer>
          <Popover
            anchor={anchorRef.current}
            idealDirection="down"
            onDismiss={() => setOpen(false)}
            positionRelativeToAnchor={false}
            size="xl"
          >
            <Box
              flex="grow"
              marginBottom={8}
              marginEnd={4}
              marginStart={4}
              marginTop={6}
              width={360}
            >
              <Flex direction="column" gap={{ column: 6, row: 0 }}>
                <Text align="center" color="default" weight="bold">
                  Invite collaborators
                </Text>
                <SearchCollaboratorsField />
              </Flex>
            </Box>
          </Popover>
        </Layer>
      )}
    </Flex>
  );
}

Keyboard Interaction

If AvatarGroup is acting as a button or link, the Tab key will focus the AvatarGroup.
Hitting the Enter or Return key opens a dialog or redirects to a new page (depending on the role) and the user can then add or view collaborators.

Localization

Be sure to localize all text strings. Note that localization can lengthen text by 20 to 30 percent.

Variants

Fixed sizes

AvatarGroup is available in 3 fixed height sizes: xs (24px), sm (32px), and md (48px).

size="xs"
size="sm"
size="md"

Responsive sizing

AvatarGroup is a responsive component. Avatar Groups that are not given a size prop or use size fit will expand to fit to the width of their parent container. A common use case is to achieve column-based sizing. Resize the width or number of avatars to see the AvatarGroup change to match the width of the Column it's been placed in.

import { AvatarGroup, Box, Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Box height={100} padding={2} width={600}>
        <Flex alignItems="center" height="100%">
          <Box column={5} height="100%">
            <AvatarGroup
              accessibilityLabel="Collaborators: Keerthi, Alberto, and Shanice."
              collaborators={[
                {
                  name: 'Keerthi',
                  src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg',
                },
                {
                  name: 'Alberto',
                  src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg',
                },
                {
                  name: 'Shanice',
                  src: 'https://i.ibb.co/7tGKGvb/shanice.jpg',
                },
              ]}
              size="fit"
            />
          </Box>
          <Box column={7} marginStart={2}>
            <Text inline>The </Text>
            <Text inline weight="bold">
              <Link
                display="inlineBlock"
                href="https://www.pinterest.com/search/boards/?q=quick%20vegan%20recipes&rs=typed&term_meta[]=quick%7Ctyped&term_meta[]=vegan%7Ctyped&term_meta[]=recipes%7Ctyped"
              >
                Quick Vegan Recipes{' '}
              </Link>
            </Text>
            <Text inline> board has 3 followers.</Text>
          </Box>
        </Flex>
      </Box>
    </Flex>
  );
}

Collaborators display

AvatarGroup displays up to three user avatars. More users, if present, will be displayed as a numerical count. Not available for 'xs' size.

Role

AvatarGroup can be display only, but can also act as a button or link. It will only be clickable if role is set to button or link. For button role, onClick is required. For link role, href is required.

role="button"
import { useRef, useState } from 'react';
import {
  Avatar,
  AvatarGroup,
  Box,
  Flex,
  Layer,
  Popover,
  Text,
  useDangerouslyInGestaltExperiment,
} from 'gestalt';

export default function Example() {
  const [open, setOpen] = useState(false);
  const anchorRef = useRef(null);
  const isInVRExperiment = useDangerouslyInGestaltExperiment({
    webExperimentName: 'web_gestalt_visualRefresh',
    mwebExperimentName: 'web_gestalt_visualRefresh',
  });

  const collaborators = [
    {
      name: 'Keerthi',
      src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg',
    },
    {
      name: 'Alberto',
      src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg',
    },
    {
      name: 'Shanice',
      src: 'https://i.ibb.co/7tGKGvb/shanice.jpg',
    },
  ];

  const collaboratorsVR = [
    {
      name: 'Fatima',
      src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg',
    },
    {
      name: 'Sora',
      src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg',
    },
    {
      name: 'Ayesha',
      src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg',
    },
  ];

  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <AvatarGroup
        ref={anchorRef}
        accessibilityLabel="Click to see group collaborators."
        collaborators={isInVRExperiment ? collaboratorsVR : collaborators}
        onClick={() => setOpen((value) => !value)}
        role="button"
        size="md"
      />
      {open && (
        <Layer>
          <Popover
            anchor={anchorRef.current}
            idealDirection="down"
            onDismiss={() => setOpen(false)}
            positionRelativeToAnchor={false}
            size="xs"
          >
            <Box
              flex="grow"
              marginBottom={8}
              marginEnd={4}
              marginStart={4}
              marginTop={6}
              width={360}
            >
              <Flex direction="column" gap={{ column: 6, row: 0 }}>
                <Text align="start" color="default" weight="bold">
                  Collaborators
                </Text>
                <Flex direction="column" gap={{ column: 2, row: 0 }}>
                  {!isInVRExperiment &&
                    collaborators.map(({ name, src }) => (
                      <Flex
                        key={name}
                        alignItems="center"
                        gap={{ row: 2, column: 0 }}
                      >
                        <Avatar name={name} size="md" src={src} />
                        <Text weight="bold">{name}</Text>
                      </Flex>
                    ))}
                  {isInVRExperiment &&
                    collaboratorsVR.map(({ name, src }) => (
                      <Flex
                        key={name}
                        alignItems="center"
                        gap={{ row: 2, column: 0 }}
                      >
                        <Avatar name={name} size="md" src={src} />
                        <Text weight="bold">{name}</Text>
                      </Flex>
                    ))}
                </Flex>
              </Flex>
            </Box>
          </Popover>
        </Layer>
      )}
    </Flex>
  );
}

role="link"
import { AvatarGroup, Flex, useDangerouslyInGestaltExperiment } from 'gestalt';

export default function Example() {
  const isInVRExperiment = useDangerouslyInGestaltExperiment({
    webExperimentName: 'web_gestalt_visualRefresh',
    mwebExperimentName: 'web_gestalt_visualRefresh',
  });

  const collaborators = [
    {
      name: 'Keerthi',
      src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg',
    },
    {
      name: 'Alberto',
      src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg',
    },
    {
      name: 'Shanice',
      src: 'https://i.ibb.co/7tGKGvb/shanice.jpg',
    },
  ];

  const collaboratorsVR = [
    {
      name: 'Fatima',
      src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg',
    },
    {
      name: 'Sora',
      src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg',
    },
    {
      name: 'Ayesha',
      src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg',
    },
  ];

  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <AvatarGroup
        accessibilityLabel="Visit group activity board."
        collaborators={isInVRExperiment ? collaboratorsVR : collaborators}
        href="#Role"
        onClick={() => {}}
        role="link"
        size="md"
      />
    </Flex>
  );
}

Component quality checklist

Component quality checklist
Quality item
Status
Status description
Figma Library
Ready
Component is available in Figma for web and mobile web.
Responsive Web
Ready
Component responds to changing viewport sizes in web and mobile web.

Avatar
Avatar is the ideal component in cases where only one person or brand needs to be displayed.