Skip to content

Conversation

@akabiru
Copy link
Member

@akabiru akabiru commented Dec 3, 2025

What are you trying to accomplish?

Enhance Primer::Beta::Avatar to render initials in a styled SVG when the avatar img src is nil/blank.

This addresses OP Core Bug https://community.openproject.org/wp/69230 whereby avatars rendered via Primer::Beta::AvatarStack do not render with appropriately styled initials.

Screenshot showing bug in OpenProject core. Previos avatars did not handle nil src gracefully

Screenshots

Screenshot of avatar preview with initials support, different sizes. Screenshot of avatar stack preview with avatars with initials support

Risk Assessment

  • Low risk the change is small, highly observable, and easily rolled back.
  • Medium risk changes that are isolated, reduced in scope or could impact few users. The change will not impact library availability.
  • High risk changes are those that could impact customers and SLOs, low or no test coverage, low observability, or slow to rollback.

What approach did you choose and why?

Use SVG data URIs with initials as fallback, keeping it as a proper <img> element maintaining semantic HTML and ensuring screen readers handle avatars consistently.

Anything you want to highlight for special attention from reviewers?

Warning

This change alters the Primer::Beta::Avatar constructor signature- needs review on whether that is acceptable for upstream (primer/view_components) syncing.

Accessibility

  • Fixes axe scan violation - This change fixes an existing axe scan violation.
  • No new axe scan violation - This change does not introduce any new axe scan violations.
  • New axe violation - This change introduces a new axe scan violation. Please describe why the violation cannot be resolved below.

Merge checklist

  • Added/updated tests
  • Added/updated documentation
  • Added/updated previews (Lookbook)
  • Tested in Chrome
  • Tested in Firefox
  • Tested in Safari
  • Tested in Edge

@changeset-bot
Copy link

changeset-bot bot commented Dec 3, 2025

🦋 Changeset detected

Latest commit: 4682247

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@openproject/primer-view-components Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@akabiru akabiru force-pushed the bug/69230-fix-avatars-with-initials branch 2 times, most recently from b6c96c5 to fe4a265 Compare December 3, 2025 09:06
@github-actions
Copy link

github-actions bot commented Dec 3, 2025

⚠️ Visual or ARIA snapshot differences found

Our visual and ARIA snapshot tests found UI differences. Please review the differences by viewing the files changed tab to ensure that the changes were intentional.

Review differences

@akabiru akabiru force-pushed the bug/69230-fix-avatars-with-initials branch from c5dc1a2 to 32c6147 Compare December 3, 2025 13:30
@akabiru akabiru force-pushed the bug/69230-fix-avatars-with-initials branch from 32c6147 to 9f3c2aa Compare December 3, 2025 13:41
@akabiru
Copy link
Member Author

akabiru commented Dec 3, 2025

Failing test is unrelated, also failing on main.

@akabiru akabiru force-pushed the bug/69230-fix-avatars-with-initials branch 2 times, most recently from 2bda67d to f65158c Compare December 4, 2025 13:52
The hash function is not consistently portable between JS/Ruby due to different "integer overflow handling (!?)".
JS based coloring establishes consistency while we have both primer legacy (angular) component rendering avatar fallback
Copy link

@brunopagno brunopagno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From where I stand it looks great! 👏

I also like that we don't depend on user or any data model to make it nice to use ❤️. I wish we could do this for most/all UI components.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the Primer::Beta::Avatar component to render initials in a styled SVG when the avatar image source is nil or blank, addressing a bug in OpenProject where avatars in AvatarStack didn't render properly without an image source. The implementation uses SVG data URIs as fallbacks while maintaining semantic HTML structure and accessibility.

Key Changes:

  • Makes src parameter optional in Avatar constructor (breaking change)
  • Adds SVG fallback generation with user initials extracted from alt text
  • Implements client-side color correction via Catalyst custom element
  • Adds comprehensive test coverage for the new fallback functionality

Reviewed changes

Copilot reviewed 13 out of 21 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
app/components/primer/beta/avatar.rb Modified Avatar component to support optional src, added SVG generation with initials, color hashing, and validation logic
app/components/primer/beta/avatar_fallback.ts New Catalyst controller for client-side SVG color correction to match OpenProject's color generation
app/components/primer/primer.ts Added import for new avatar_fallback TypeScript module
test/components/beta/avatar_test.rb Added 14 comprehensive tests covering fallback rendering, initials generation, color consistency, shapes, and edge cases
previews/primer/beta/avatar_preview.rb Added 6 new Lookbook previews demonstrating fallback functionality
previews/primer/beta/avatar_stack_preview.rb Added 2 new previews showing fallback avatars in stacks
previews/primer/beta/avatar_preview/*.html.erb New ERB templates for fallback preview rendering
.changeset/heavy-donuts-bow.md Added changeset describing the enhancement (incorrectly marked as minor)
.playwright/screenshots/* New visual regression test snapshots for fallback avatars

Copy link
Collaborator

@myabc myabc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing flickering behaviour when fallback avatars are rendered in an Avatar Stack.

Screen.Recording.2025-12-10.at.14.07.25.mov

http://localhost:4000/lookbook/inspect/primer/beta/avatar_stack/more_options

Chrome 143.0.7499.41 (Official Build) (arm64)
macOS Tahoe 26.1 (25B78)

Copy link
Collaborator

@myabc myabc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in giving feedback... 🙏🏻

General feedback - Part 1

Even though upstream/GitHub PVC is less of a moving target than before, I still think we need to set a very high bar when it comes to modifying upstream components directly.

In my opinion, we should only modify Primer::Alpha/Primer::Beta components directly when:

  • EITHER the behaviour changes are generic and/or the fixes are of potential use to other library consumers and there is a likelihood we can upstream.
  • OR any API changes are purely additive / very limited.

I don't think this change meets the above criteria. Instead, I think we should prefer Extension Over Mutation.

Instead of modifying Primer::Beta::Avatar directly, could we not introduce a Primer::OpenProject::Avatar or AvatarWithFallback component that decorates or is composed of a Primer::Beta::Avatar?

I realise the disadvantage of the above is that we would also have to reimplement or extend AvatarStack to make this work - since slots are fussy about their type

@myabc myabc self-requested a review December 10, 2025 18:19
Copy link
Collaborator

@myabc myabc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General feedback - Part 2

I’m not keen on rendering in Rails and then adjusting the colour in JavaScript. That gives us two parallel codepaths (Ruby and TS) doing essentially the same work, with subtle colour differences due to hashing/overflow behaviour. It adds avoidable complexity and may introduce FOUC.

I think we should pick one direction:

  1. Unify everything in Ruby by resolving the hashing/colour-generation differences (if that's possible); or
  2. Make the server-side output minimal, e.g., render only a correctly sized placeholder circle to prevent reflow, and leave initials/colour entirely to the client.

If we keep server-side rendering, generate_fallback_svg and related methods should be extracted—either into a FallbackAvatarComponent or a small module with module_functions.

If we go with 2, then this begs the question as to whether we shouldn't just reuse the Angular implementation. If we do then this component probably belongs back in core for now.

@akabiru akabiru marked this pull request as draft December 15, 2025 08:33
@akabiru akabiru self-assigned this Dec 15, 2025
akabiru and others added 2 commits December 18, 2025 12:58
Make `avatar-fallback` invisible to the layout system, removing them from the document flow.
This allows the child .avatar img(s) to behave as if they are direct children of `.Avatar-body`
@akabiru
Copy link
Member Author

akabiru commented Dec 18, 2025

Thanks once more @myabc , those issues were definitely missed! Please review these changes that address the following:

op-avatar-demo.mp4

@akabiru akabiru requested a review from myabc December 18, 2025 11:04
@akabiru akabiru changed the title bug/69230 Enhance Primer::Beta::Avatar to render initials in a styled SVG when avatar img src is nil/blank bug/69230 Extend Primer::Beta::Avatar as Primer::OpenProject::AvatarWithFallback to render initials in a styled SVG when avatar img src is nil/blank Dec 18, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 7 comments.

@akabiru akabiru force-pushed the bug/69230-fix-avatars-with-initials branch 3 times, most recently from a4ddaed to c692e44 Compare January 5, 2026 11:01
@akabiru akabiru force-pushed the bug/69230-fix-avatars-with-initials branch from 8e8817d to 9a5608c Compare January 5, 2026 11:07
@akabiru akabiru merged commit 55ed98f into main Jan 5, 2026
27 of 30 checks passed
@akabiru akabiru deleted the bug/69230-fix-avatars-with-initials branch January 5, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

5 participants