Avatar and Avatar Group
الصورة الرمزية ومجموعتها<img alt> / AvatarGroup
also calledprofile picture، user avatar، initials avatar، avatar stack، facepile، profile photo، أفاتار، الصورة الشخصية، صورة المستخدم، بديل الحروف الأولى، صفّ الصور المتداخلة، أيقونة الحساب
An avatar is the small graphic that identifies one named entity: a person, a team, or a company. It shows a picture when there is one, and falls back to the initials of the name on a coloured ground when there is none or when the file fails to load. The shape carries meaning ahead of any label: a circle for people, a rounded square for organisations, and mixing the two inside one list throws that signal away. An avatar is not an icon, because an icon names an action or a type (delete, folder, settings) and the same drawing is reused everywhere, while an avatar points at one specific entity and is simply wrong on anyone else. It is not a badge: a badge is a count or a state stuck onto another element in order to describe it, whereas the avatar is the element rather than the decoration on it. It is not a chip either, since a chip spells the name out in letters, usually carries a remove button, and lives inside an input. An avatar group is a row of overlapping avatars that answers "who is on this?" at a glance, and it summarises a list instead of replacing one, so put a real list behind the counter when the user needs the names.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
يعملون على «خطة الربع الرابع»
Anatomy: every part, named
Hover a row to locate it in the demo above.
Build prompt
How it behaves right-to-left
This section is ours alone.
Which way the row overlaps
mirrorsIn English the first avatar sits at the left and each next one slides under it toward the right. In Arabic the whole row turns around: the first avatar is at the right and the row grows to the left. Write the offset as margin-inline-start: -8px on every avatar except the first, so each one is pulled toward whichever side "previous" happens to be on. A margin-left: -8px keeps pulling left after the flip, so each avatar slides under the one that comes after it instead of the one before it, the first two end up flush with no overlap at all, and the last one drags the far edge of the row 8px inward. Do not patch that with a margin-right inside [dir="rtl"]; the logical property already covers both directions.
Stacking order
never mirrorsThe look where each avatar tucks under the one before it comes from a z-index that runs against DOM order: the first gets the highest value and the last the lowest, because the browser otherwise paints a later sibling over an earlier one and the effect inverts. Those values stay put when the page flips. z-index is a painting property rather than a layout one and has no logical form at all, so re-reversing it inside [dir="rtl"] lifts the last avatar above everything and the row reads inverted. What does move is the hidden crescent of each circle: it stays at the logical start, sitting on the left edge of each avatar in English and on the right edge in Arabic. Avoid the flex-direction: row-reverse trick with reversed DOM order for getting this look, because row-reverse is resolved against direction and turns the entire Arabic row around.
The status dot corner
mirrorsThe dot belongs in the bottom corner at the logical end: bottom right in English, bottom left in Arabic. Anchor it with inset-inline-end: 0 and inset-block-end: 0 rather than right: 0. The trap is the small nudge that pushes the dot out over the edge, because transform has no logical form at all: a positive X in translate(25%, 25%) always moves right, so once the anchor lands on the left side in Arabic the same nudge creeps the dot inward across the face instead of outward. Multiply the horizontal axis by a --dir sign set to -1 under [dir="rtl"], or drop the transform and use inset-inline-end: -2px. If a library places the badge with a value named "left" or "right", that name is physical: MUI resolves anchorOrigin against theme.direction, so check whether yours does the same before you trust it to flip on its own.
The counter and its plus sign
mirrorsThe counter stands at the logical end of the row, so it moves from the far right in English to the far left in Arabic. That happens by itself when the row is an ordinary flex container and the chip is last in the DOM. If instead you laid the avatars out with position: absolute and left: calc(i * 20px), move that calc to inset-inline-start or the counter parks on top of the first avatar. The text needs a separate fix from the layout. A plus sign has no direction of its own: U+002B carries bidi class ES, which is weak rather than strong or neutral, so the algorithm hands it the direction of whatever surrounds it and a token typed as "+3" paints as "3+" on an Arabic line. That is the algorithm working correctly and still not what the design drew, so wrap the token in a span with dir="ltr", an attribute the HTML user-agent stylesheet already gives unicode-bidi: isolate, or write the count out in words.
What never mirrors: photo and initials
never mirrorsA photograph is content, not chrome. The blanket rule some teams write to flip icons, [dir="rtl"] img, [dir="rtl"] svg { transform: scaleX(-1) }, catches every face and every logo, including the lettering drawn inside the logo. Scope the flip to a class you put on arrows only. object-position accepts physical keywords only, and here that is the right behaviour, since the crop belongs to the picture rather than to the page: object-position: right center still means the right edge of the file after the flip, which is what you want. The initials are plain text whose order the bidi algorithm already decides, so never reverse the string yourself for Arabic, and centre it with text-align: center so a one letter fallback does not sit somewhere different from a two letter one.
In code
Each row is one framework's word for the same thing. Take the row your project speaks.
See also
Updated · 2026-08-19