Skip to content

fix(ui): render the Avatar fallback as a blank placeholder - #9398

Merged
alexcarpenter merged 4 commits into
mainfrom
carp/avatar-skeleton-fallback
Aug 11, 2026
Merged

fix(ui): render the Avatar fallback as a blank placeholder#9398
alexcarpenter merged 4 commits into
mainfrom
carp/avatar-skeleton-fallback

Conversation

@alexcarpenter

@alexcarpenter alexcarpenter commented Aug 11, 2026

Copy link
Copy Markdown
Member

Description

Avatar.Fallback keeps its API — it still takes children, initials or an icon — but it no longer paints them. The children move into a new avatar-fallback-content slot held at visibility: hidden, so what's left is the neutral fill on its own. visibility is the one property that takes the content out of the page, the accessibility tree, and the tab order together, and unlike inert it leaves hit-testing alone, so a click still reaches the button row these sit in. A consumer who wants the initials back overrides that one slot.

The fallback also pulses now, but only while an image is genuinely on its way (status === 'loading', reflected as data-pending). Someone who simply has no picture is not waiting on anything, so their mark holds still rather than pulsing for as long as it's on screen. The pulse matches skeleton.tsx's timing and drops to none under prefers-reduced-motion.

user-button.view.tsx is comments only — it still computes and passes initials(name), so the name is there for anyone who styles the slot back into view.

Swingset gets a Pending example. /api/pending-image holds its response for a minute with cache-control: no-store, so the pulse is the component's own status rather than a pinned attribute.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Avatar.Fallback still takes children, but it no longer paints them: an
entity without a picture reads as an absent image rather than as two
letters. The children move into an `avatar-fallback-content` slot held at
`visibility: hidden`, which takes them out of the page, the accessibility
tree, and the tab order at once while leaving hit-testing alone, so a
consumer can style them back into view.

The fallback pulses only while an image is genuinely resolving
(`data-pending`); someone who has no picture is not waiting on anything,
so their mark holds still.
@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d013999

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview Aug 11, 2026 6:11pm
swingset Ready Ready Preview Aug 11, 2026 6:11pm

Request Review

@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9398

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9398

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9398

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9398

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9398

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9398

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9398

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9398

@clerk/expo-google-signin

npm i https://pkg.pr.new/@clerk/expo-google-signin@9398

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9398

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9398

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9398

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9398

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9398

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9398

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9398

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9398

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9398

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9398

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9398

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9398

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9398

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9398

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9398

commit: d013999

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-08-11T18:13:20.778Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 0
🔴 Breaking changes 0
🟡 Non-breaking changes 0
🟢 Additions 0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on d013999.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 528247a8-b031-4843-a13b-d341dea903a3

📥 Commits

Reviewing files that changed from the base of the PR and between 207eecd and d013999.

📒 Files selected for processing (6)
  • packages/swingset/src/app/api/pending-image/route.ts
  • packages/swingset/src/stories/avatar.stories.tsx
  • packages/ui/src/mosaic/components/avatar/avatar.styles.ts
  • packages/ui/src/mosaic/components/avatar/avatar.test.tsx
  • packages/ui/src/mosaic/user-button/__tests__/user-button.view.test.tsx
  • packages/ui/src/mosaic/user-button/user-button.view.tsx
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/cli (auto-detected)
  • clerk/clerk-ios (auto-detected)
  • clerk/clerk-android (auto-detected)
💤 Files with no reviewable changes (1)
  • packages/swingset/src/stories/avatar.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/ui/src/mosaic/user-button/tests/user-button.view.test.tsx
  • packages/ui/src/mosaic/components/avatar/avatar.test.tsx
  • packages/ui/src/mosaic/components/avatar/avatar.styles.ts
  • packages/ui/src/mosaic/user-button/user-button.view.tsx
  • packages/swingset/src/app/api/pending-image/route.ts

📝 Walkthrough

Walkthrough

Avatar fallbacks now hide fallback content by default and wrap it in a dedicated content slot. The fallback exposes pending state while an image request remains unresolved, applies a pulse animation, and stops pulsing after an error. Tests cover pending, error, and no-source states. A pending-image endpoint and story demonstrate the behavior. Avatar documentation and user-button comments were updated. An empty Changeset file was added.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: maxyinger

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main Avatar fallback behavior change.
Description check ✅ Passed The description accurately explains the hidden fallback content, pending pulse behavior, tests, and example changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/mosaic-avatar-skeleton-fallback.md:
- Around line 1-2: Add an `@clerk/ui` changeset entry in
mosaic-avatar-skeleton-fallback.md with the appropriate release bump and a
concise release note describing the updated default Avatar.Fallback output; do
not leave the changeset empty.

In `@packages/swingset/src/app/api/pending-image/route.ts`:
- Around line 17-29: Add unit tests covering the GET route’s delayed response
contract: use fake timers to verify normal resolution after HOLD_MS and
request-signal cancellation before the delay completes, and assert both PNG
content type and no-store cache-control headers for the returned Response.

In `@packages/ui/src/mosaic/components/avatar/avatar.styles.ts`:
- Around line 5-7: Reduce comments across the listed sites to only terse
non-obvious rationale: in avatar.styles.ts lines 5-7 and 53-58, replace each
explanation with one concise rationale line, and remove lines 63-64; remove
narration at avatar.test.tsx lines 16-18, 228-230, and 261-262; shorten the
accessibility and avatarName comments in user-button.view.tsx lines 135-136 and
186-188, remove lines 157-158 and 683, and remove narration in
user-button.view.test.tsx lines 653-654; shorten the route-purpose and cache
comments in pending-image/route.ts lines 1-4 and 13-14, remove line 7; and
remove the story narration in avatar.stories.tsx lines 49-50. Preserve code
behavior and leave comments only where they explain non-obvious rationale.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: ea7ed4b3-ea6a-424f-80b8-5477ae8450cd

📥 Commits

Reviewing files that changed from the base of the PR and between 3132d40 and 07a07ba.

📒 Files selected for processing (9)
  • .changeset/mosaic-avatar-skeleton-fallback.md
  • packages/swingset/src/app/api/pending-image/route.ts
  • packages/swingset/src/stories/avatar.mdx
  • packages/swingset/src/stories/avatar.stories.tsx
  • packages/ui/src/mosaic/components/avatar/avatar.styles.ts
  • packages/ui/src/mosaic/components/avatar/avatar.test.tsx
  • packages/ui/src/mosaic/components/avatar/avatar.tsx
  • packages/ui/src/mosaic/user-button/__tests__/user-button.view.test.tsx
  • packages/ui/src/mosaic/user-button/user-button.view.tsx
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/cli (auto-detected)
  • clerk/clerk-ios (auto-detected)
  • clerk/clerk-android (auto-detected)

Comment thread .changeset/mosaic-avatar-skeleton-fallback.md
Comment thread packages/swingset/src/app/api/pending-image/route.ts
Comment thread packages/ui/src/mosaic/components/avatar/avatar.styles.ts Outdated
@alexcarpenter
alexcarpenter merged commit a9099bc into main Aug 11, 2026
52 checks passed
@alexcarpenter
alexcarpenter deleted the carp/avatar-skeleton-fallback branch August 11, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants