Feature #44717
openLet users choose the colour of their initials avatar from the palette
Description
Problem¶
Since 6.1.0 (#29824) the colour of the initials avatar is derived from user.id % 8 in AvatarsHelper#initials_avatar_tag. The user has no way to influence it, and that has two practical consequences:
- Two users with the same initials whose ids are congruent modulo 8 get exactly the same avatar: same letters, same colour. The avatar then fails at its main job, telling people apart at a glance in issue lists, on the activity page and in the watchers list, and the collision gets more likely as the user base grows.
- Users are stuck for good with whatever colour their id happened to produce. Colour is a personal thing, and the only remedy today is an administrator changing the theme for everyone.

Mock-up with fictitious names: two different assignees with the same initials and ids congruent modulo 8 get the same avatar.
Feature #12197 (7.1.0) lets users upload a picture instead, but the initials avatar remains the default, and the only option wherever ImageMagick is missing, uploads are disabled by policy, or users simply do not want a photo. With #44684 it also becomes the fallback for Gravatar users without an image. Most users will therefore keep seeing it, so it is worth making it something they can choose.
Proposal¶
Add a per-user setting that selects one of the existing palette classes avatar-color-0 to avatar-color-7. The user chooses an index, not a colour value, so:
- Colours stay CSS classes. Themes keep full control of the actual values, which was the design constraint Felix Schäfer set out in #29824 (inline styles would make it impossible for theme authors to adjust the colours to their theme).
- No new colour or contrast handling is needed: each class already carries its matching text colour.
- The default stays
user.id % 8, so nothing changes for anyone until they pick a colour. - A later extension of the palette, listed as a future improvement in #29824, just becomes a longer swatch row.
UI¶
On the avatar page introduced by #12197 (/my/avatar, and /users/:id/avatar for administrators), below the preview, a row of radio buttons labelled "Colour". Each option is rendered as the initials avatar itself with the respective avatar-color-N class and the user's own initials, so the user sees the real result, and the current colour is pre-selected. The row is shown whenever the initials avatar is in use or would be the fallback, and unlike the upload form it works without ImageMagick.
If the avatar page is considered upload specific, the same control fits in app/views/users/_preferences.html.erb, which is already shared between My account and the administrator's user form.
![]()
Avatar page as it is on trunk (mock-up built from the #12197 template).
![]()
The same page with the proposed Colour row. The current colour is pre-selected.
Implementation sketch¶
- Migration:
add_column :users, :avatar_color, :integer, nullable. A column onusersrather than an entry inUserPreference#others, for the same reason #12197 putavatar_idthere: avatars are rendered for many different users on every list page, and reading a preference row for each of them would add one query per user. User: addavatar_colortosafe_attributesand validate it withinclusion: 0...AvatarsHelper::INITIALS_AVATAR_COLORS, allow_nil: true.AvatarsHelper: a constantINITIALS_AVATAR_COLORS = 8as the single place where the palette size is defined, and ininitials_avatar_tag:
color = user.avatar_color
color = user.id % INITIALS_AVATAR_COLORS unless color && color.between?(0, INITIALS_AVATAR_COLORS - 1)
css_class = ["avatar-color-#{color}", "s#{size}", options[:class]].compact.join(' ')
The range check keeps a stored value from breaking the display if the palette ever shrinks.
AvatarsController: a separate action for saving the colour (e.g.PUT /my/avatar/color), because the existingupdatesits behindcheck_avatar_availableand colour selection must work without ImageMagick.- Locale: one new string,
field_avatar_color. - REST API: expose
avatar_coloron the user resource, optionally as a follow-up.
Out of scope¶
- Random assignment at user creation: not needed,
user.id % 8already spreads the colours and is stable. - Free colour input: deliberately excluded, so that themes stay in control and text contrast stays guaranteed.
Files