Skip to content

refactor: Updated fallback behavior for avatar token, network, and favicon#1212

Merged
brianacnguyen merged 6 commits into
mainfrom
refactor/avatar-fallbacks
Jun 4, 2026
Merged

refactor: Updated fallback behavior for avatar token, network, and favicon#1212
brianacnguyen merged 6 commits into
mainfrom
refactor/avatar-fallbacks

Conversation

@brianacnguyen

@brianacnguyen brianacnguyen commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Description

Improves avatar placeholder behavior across AvatarFavicon, AvatarNetwork, and AvatarToken in both @metamask/design-system-react and @metamask/design-system-react-native.

Why: When no src was provided, image-based avatars rendered an empty placeholder because fallback text was only set after an image load error. Avatars without a name or fallbackText also showed nothing instead of a meaningful default.

What changed:

  1. Immediate fallback when src is missing — Avatars now show fallbackText, the first character of name, or ? right away when there is no image source, instead of waiting for an error that never occurs.
  2. Default placeholder character — The final fallback default is now ? instead of an empty string when neither fallbackText nor name is provided.
  3. AvatarBase background token — Updated the default background from bg-section to bg-alternative so placeholders are visible on section-colored surfaces.
  4. Storybook coverage — Added Fallback stories for all three avatar variants on web and mobile to document and manually verify placeholder states.

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-774

Manual testing steps

  1. Web Storybook — Run yarn storybook and open AvatarFavicon, AvatarNetwork, and AvatarToken.
  2. Open the new Fallback story for each component and confirm:
    • Custom fallbackText is shown when provided (e.g. "OS", "ETH", "BTC").
    • First letter of name is shown when fallbackText is omitted (e.g. "G" for Github, "A" for Arbitrum).
    • ? is shown when neither src, name, nor fallbackText is provided.
  3. React Native Storybook — Run yarn storybook:ios or yarn storybook:android and repeat the same checks on the Fallback stories.
  4. Confirm existing Src / sample stories still render images correctly and fall back to text on image load failure.
  5. Confirm AvatarBase placeholders use the bg-alternative background and remain readable on section backgrounds.

Screenshots/Recordings

Before

Simulator Screenshot - iPhone 15 Pro Max - 2026-06-02 at 12 37 18 Simulator Screenshot - iPhone 15 Pro Max - 2026-06-02 at 12 37 19 Simulator Screenshot - iPhone 15 Pro Max - 2026-06-02 at 12 36 27 Simulator Screenshot - iPhone 15 Pro Max - 2026-06-02 at 12 36 45

After

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2026-06-02.at.22.36.47.mov

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs
  • I've completed the PR template to the best of my ability
  • I’ve included tests if applicable (AvatarBase unit tests updated for bg-alternative)
  • I’ve documented my code using JSDoc format if applicable (not needed — no new APIs)
  • I’ve applied the right labels on the PR (see labeling guidelines). Not required for external contributors.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Low Risk
Design-system UI and placeholder behavior only; no auth, data, or API surface changes beyond visual fallback semantics.

Overview
Image avatars (AvatarFavicon, AvatarNetwork, AvatarToken) on web and React Native now show placeholders immediately when src is missing, using fallbackText, the first letter of name, or ? instead of staying blank until a load error. The same ? default applies after image/SVG failures when neither name nor fallback is set.

AvatarBase default background changes from bg-section to bg-alternative so placeholders read on section surfaces; RN tests and both platforms’ implementations are updated.

Storybook gains Fallback stories; tests assert no-src behavior and use text queries for error fallbacks. RN ImageOrSvg image error typing moves to ImageErrorEvent; web AvatarToken ensures onError runs after imageProps spread.

Reviewed by Cursor Bugbot for commit 96f729e. Bugbot is set up for automated code reviews on this repo. Configure here.

@brianacnguyen brianacnguyen self-assigned this Jun 3, 2026
@brianacnguyen brianacnguyen requested a review from a team as a code owner June 3, 2026 16:33
@brianacnguyen brianacnguyen changed the title Updated fallback behavior for avatar token, network, and favicon refactor: Updated fallback behavior for avatar token, network, and favicon Jun 3, 2026
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall 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.

Nice work tightening up the avatar fallback behavior. The main behavior looks good and the focused React/React Native avatar tests pass locally with coverage disabled. I left a few non-blocking comments around handler ordering, RN test assertions, and a deprecated RN image error type.

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall 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.

LGTM! Nice work 🚀

@brianacnguyen brianacnguyen merged commit 4979aeb into main Jun 4, 2026
36 checks passed
@brianacnguyen brianacnguyen deleted the refactor/avatar-fallbacks branch June 4, 2026 00:04
@georgewrmarshall georgewrmarshall mentioned this pull request Jun 4, 2026
18 tasks
georgewrmarshall added a commit that referenced this pull request Jun 4, 2026
## Release 43.0.0

This release drops Node.js 18 support across the release line, adds
several new components, and includes a small set of breaking API changes
that are documented in the migration guides.

### 📦 Package Versions

- `@metamask/design-system-shared`: **0.21.0**
- `@metamask/design-system-react`: **0.25.0**
- `@metamask/design-system-react-native`: **0.28.0**
- `@metamask/design-tokens`: **8.5.0**
- `@metamask/design-system-tailwind-preset`: **0.9.0**
- `@metamask/design-system-twrnc-preset`: **0.5.0**

### 🔄 Shared Type Updates (0.21.0)

#### Added

- Added `ContentPropsShared` and `ContentVerticalAlignment` for React
Native list-style rows and related layout patterns
([#1192](#1192))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- **BREAKING:** Updated `TextAreaPropsShared` to remove `inputElement`
so React Native `TextArea` can render the root `TextInput` directly
([#1205](#1205))

### 🌐 React Web Updates (0.25.0)

#### Added

- Added `Popover` for anchored overlays such as menus, tooltips, and
dialogs
([#1153](#1153))
- Added `TextArea` for controlled multiline text entry
([#1036](#1036))
- Added `TextFieldSearch` for controlled search-field flows on top of
`TextField`
([#1171](#1171))
- Added `FormTextField` for labeled form controls built from `Label`,
`TextField`, and `HelpText`
([#1197](#1197))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- Updated avatar fallback handling so `AvatarToken`, `AvatarNetwork`,
and `AvatarFavicon` resolve consistently when the requested image is
unavailable
([#1212](#1212))

### 📱 React Native Updates (0.28.0)

#### Added

- Added `Content` for composing scrollable and padded content sections
on React Native screens; it is closely related to the upcoming
`ListItem` work
([#1192](#1192))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- Added default padding and `isInteractive` support to `SectionHeader`
so section rows match the new mobile layout patterns
([#1210](#1210))
- **BREAKING:** Flattened `TextArea` so it renders the root `TextInput`
directly; pass `TextInput` props on `TextArea`, use the component `ref`
for the input, and stop relying on `inputProps` or `inputElement`
([#1205](#1205))
- Updated avatar fallback handling so `AvatarToken`, `AvatarNetwork`,
and `AvatarFavicon` resolve consistently when the requested image is
unavailable
([#1212](#1212))

### ⚠️ Breaking Changes

#### Node.js 18 support removed

**What Changed:**

- The release line now requires Node 20 or newer.
- This applies across the monorepo, including the shared package, web
package, React Native package, tokens, and both preset packages.

**Impact:**

- Consumers still on Node 18 must upgrade their runtime before
installing or developing against this release line.
- Node 18 is end-of-life, so this change aligns the repo with the
supported app runtimes.

#### React Native `TextArea` flattening

**What Changed:**

- `TextArea` now renders the root `TextInput` directly.
- `inputProps` and `inputElement` are removed.
- `inputRef` is replaced by the component `ref`.

**Migration:**

```tsx
// Before (0.27.0)
<TextArea
  inputProps={{ placeholder: 'Message' }}
  inputElement={<CustomInput />}
/>

// After (0.28.0)
<TextArea placeholder="Message" ref={inputRef} />
```

**Impact:**

- Affects React Native consumers using `TextArea`.
- Call sites that depended on the wrapper/input split need to be
updated.

See migration guides for complete instructions:

- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0220-to-0230)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0270-to-0280)

### ✅ Checklist

- [x] Changelogs updated with human-readable descriptions
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] Version bumps follow semantic versioning
- [x] design-system-shared: minor (0.20.0 → 0.21.0) - shared type
additions and breaking TextArea/shared runtime baseline
- [x] design-system-react: minor (0.24.0 → 0.25.0) - new components and
release-line update
- [x] design-system-react-native: minor (0.27.0 → 0.28.0) - new
component, SectionHeader update, and breaking TextArea change
- [x] Breaking changes documented with migration guidance
- [x] Migration guides updated with before/after examples (if breaking
changes)
- [x] PR references included in changelog entries

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs)
- [x] I've reviewed the [Release
Workflow](./.cursor/rules/release-workflow.md) cursor rule
- [ ] All tests pass (`yarn build && yarn test && yarn lint`)
- [x] Changelog validation passes (`yarn changelog:validate`)

## **Pre-merge reviewer checklist**

- [x] I've reviewed the [Reviewing Release
PRs](./docs/reviewing-release-prs.md) guide
- [x] Package versions follow semantic versioning
- [x] Changelog entries are consumer-facing (not commit message
regurgitation)
- [x] Breaking changes are documented in MIGRATION.md with examples
- [x] All unreleased changes are accounted for in changelogs

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Breaking React Native TextArea and Node 18 removal affect consumer
upgrades; most diff is release metadata with coordinated peer dependency
bumps.
> 
> **Overview**
> **Release 43.0.0** bumps the monorepo root to **43.0.0** and publishes
coordinated semver bumps across design-system packages, with
**yarn.lock** peer ranges updated for
`@metamask/design-system-tailwind-preset` **^0.9.0** and
`@metamask/design-system-twrnc-preset` **^0.5.0**.
> 
> Across the release line, changelogs record **Node.js 18 dropped**
(Node **20+** required). **@metamask/design-system-react** **0.25.0**
documents new **`Popover`**, **`TextArea`**, **`TextFieldSearch`**, and
**`FormTextField`**, plus avatar fallback fixes.
**@metamask/design-system-react-native** **0.28.0** adds **`Content`**,
updates **`SectionHeader`** (default padding, **`isInteractive`**), and
includes a **breaking** **`TextArea`** flattening (`inputProps` /
`inputElement` / `inputRef` removed; props and **`ref`** target the root
**`TextInput`**). **@metamask/design-system-shared** **0.21.0** adds
**`ContentPropsShared`** / **`ContentVerticalAlignment`** and removes
**`inputElement`** from shared **`TextArea`** props.
> 
> Migration guide edits in this diff: React Native **0.27.0 → 0.28.0**
**`TextArea`** guidance; React version heading **0.22.0 → 0.23.0** for
**`BannerBase`** (changelog-driven **0.25.0** items are not new
migration sections here).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
23b0cda. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants