Skip to content

feat(ui): add AccountButton view component#9184

Open
alexcarpenter wants to merge 4 commits into
mainfrom
carp/account-button-switcher
Open

feat(ui): add AccountButton view component#9184
alexcarpenter wants to merge 4 commits into
mainfrom
carp/account-button-switcher

Conversation

@alexcarpenter

@alexcarpenter alexcarpenter commented Jul 16, 2026

Copy link
Copy Markdown
Member

New Mosaic AccountButton: account + org switcher (multi-session + org select/suggest/invite) behind a popover. Presentational view only; controller is follow-up.

  • flat exports AccountButtonRoot/Trigger/Popup + all-in-one AccountButton
  • new popover primitive bridge; ported icon glyphs to mosaic registry
  • swingset docs: Default/Personal/MultipleAccounts

Deferred: useAccountButtonController(), pagination, real avatars.
Note: added optional onUpgrade (design shows Upgrade link); accent purple hardcoded (no token yet).

Summary by CodeRabbit

  • New Features

    • Added an Account Button that combines account and organization switching in one popover.
    • Supports personal accounts, multiple accounts, organizations, organization suggestions, and invitations.
    • Includes actions for joining organizations, accepting invitations, signing out, and switching contexts.
    • Provides both a ready-to-use component and composable options for customized layouts.
    • Added theme customization through appearance elements.
  • Documentation

    • Added usage guidance and interactive examples covering common account and organization scenarios.

@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: dfae67d

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

This PR includes changesets to release 3 packages
Name Type
@clerk/ui Minor
@clerk/chrome-extension Patch
@clerk/swingset Patch

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 Jul 16, 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, Comment Jul 16, 2026 9:17pm
swingset Ready Ready Preview, Comment Jul 16, 2026 9:17pm

Request Review

@github-actions github-actions Bot added the ui label Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

AccountButton Mosaic component

Layer / File(s) Summary
AccountButton component and Mosaic infrastructure
packages/ui/src/mosaic/components/account-button.view.tsx, packages/ui/src/mosaic/primitives/popover.tsx, packages/ui/src/mosaic/icons/registry.tsx
Adds the AccountButton data contracts, slot recipe, context-driven compound components, popover integration, account/workspace sections, and supporting icons.
Storybook and documentation integration
packages/swingset/src/stories/account-button.*, packages/swingset/src/lib/registry.ts, packages/swingset/src/components/DocsViewer.tsx, .changeset/account-button-switcher.md
Adds three fixture stories, MDX usage and styling documentation, registry and viewer entries, and a minor package changeset.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AccountButton
  participant AccountButtonRoot
  participant Popover
  participant AccountButtonPopup
  AccountButton->>AccountButtonRoot: compose data and callbacks
  AccountButtonRoot->>Popover: configure open state
  AccountButtonPopup->>Popover: render popup portal
  AccountButtonPopup->>AccountButtonRoot: read account context
Loading

Poem

I’m a rabbit with accounts in a row,
Switching through workspaces wherever they go.
With icons that sparkle and popovers bright,
Stories hop forward to document the flight.
A tiny soft thump: the new button is born!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding the new AccountButton UI component.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/electron

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

@clerk/electron-passkeys

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

@clerk/eslint-plugin

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

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

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

@clerk/upgrade

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

@clerk/vue

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

commit: dfae67d

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T21:19:13.079Z

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 dfae67d.

@vercel
vercel Bot temporarily deployed to Preview – clerk-js-sandbox July 16, 2026 21:08 Inactive

@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: 7

🤖 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 `@packages/swingset/src/lib/registry.ts`:
- Around line 3-8: Update the manually constructed AccountButton story module to
preserve the story’s raw __source export. Import __source from
account-button.stories and include it in the module object alongside
AccountButtonDefault, AccountButtonMultipleAccounts, AccountButtonPersonal, and
accountButtonMeta; apply the same change to the corresponding second
construction.

In `@packages/swingset/src/stories/account-button.mdx`:
- Around line 3-21: Restructure the AccountButton MDX documentation into
Archetype C format: replace the current descriptive sections with one short
paragraph covering owned state and the wired lower-layer pieces, then provide
exactly one Story. Add a composition array to that Story listing each direct
dependency, including the headless popover primitive and slot recipes, and
remove the current multi-story layout.

In `@packages/swingset/src/stories/account-button.stories.tsx`:
- Around line 10-14: Update the AccountButton story metadata to assign
accountButtonRecipe to meta.styles. In each story function, cast the knobs
Record<string, unknown> through knobsAsProps and spread the resulting props into
AccountButton so playground values are applied.

In `@packages/ui/src/mosaic/components/account-button.view.tsx`:
- Around line 446-808: Split the presentational leaves and sections from
account-button.view.tsx into focused React modules, extracting symbols such as
Avatar, Row, Header, WorkspaceList, AccountsSection, and Footer while preserving
their current behavior and context usage. Keep the public compound component
composition and exports in account-button.view.tsx, and update imports as needed
so the file remains focused and within the project’s preferred component size.
- Around line 21-85: Add comprehensive customer-facing JSDoc to the exported
AccountButtonAccount, AccountButtonMembership, AccountButtonSuggestion,
AccountButtonInvitation, AccountButtonData, AccountButtonCallbacks, and props
contracts, documenting field semantics including onUpgrade. Add explicit
React.JSX.Element return types to all four exported AccountButton components,
then request Docs-team review for the generated public API documentation.
- Around line 57-68: Remove the inert status field from AccountButtonData for
v1, since the current loading value still requires and renders ready-state data.
Update AccountButton consumers, including the account-button view, to rely on
the existing ready-state shape without status checks; only retain status if you
introduce a genuine discriminated union with a separate loading rendering path.
- Around line 488-535: Update the selection control rendered by Row to expose
its active state through the appropriate aria-current attribute, using the
active prop’s value. Apply the attribute to the interactive button and the
non-interactive div consistently, while leaving the visual check icon behavior
unchanged.
🪄 Autofix (Beta)

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), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 05507a88-c836-4e0f-b43f-e0d914595582

📥 Commits

Reviewing files that changed from the base of the PR and between b37ba0d and b6f96ae.

📒 Files selected for processing (8)
  • .changeset/account-button-switcher.md
  • packages/swingset/src/components/DocsViewer.tsx
  • packages/swingset/src/lib/registry.ts
  • packages/swingset/src/stories/account-button.mdx
  • packages/swingset/src/stories/account-button.stories.tsx
  • packages/ui/src/mosaic/components/account-button.view.tsx
  • packages/ui/src/mosaic/icons/registry.tsx
  • packages/ui/src/mosaic/primitives/popover.tsx

Comment on lines +3 to +8
import {
Default as AccountButtonDefault,
meta as accountButtonMeta,
MultipleAccounts as AccountButtonMultipleAccounts,
Personal as AccountButtonPersonal,
} from '../stories/account-button.stories';

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve __source when constructing the story module.

The story exports its raw source, but this manually built module drops it, preventing AccountButton code footers from rendering.

Proposed fix
 import {
+  __source as accountButtonSource,
   Default as AccountButtonDefault,
   meta as accountButtonMeta,
   MultipleAccounts as AccountButtonMultipleAccounts,
   Personal as AccountButtonPersonal,
 } from '../stories/account-button.stories';

 const accountButtonModule: StoryModule = {
   meta: accountButtonMeta,
+  __source: accountButtonSource,
   Default: AccountButtonDefault,

As per path instructions, Components-layer stories export __source to enable code footers.

Also applies to: 130-135

🤖 Prompt for 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.

In `@packages/swingset/src/lib/registry.ts` around lines 3 - 8, Update the
manually constructed AccountButton story module to preserve the story’s raw
__source export. Import __source from account-button.stories and include it in
the module object alongside AccountButtonDefault, AccountButtonMultipleAccounts,
AccountButtonPersonal, and accountButtonMeta; apply the same change to the
corresponding second construction.

Source: Path instructions

Comment on lines +3 to +21
# AccountButton

The account & organization switcher that sits behind the user button. The active account sits at the
top with its organizations (including any **suggested** workspaces you can Join), and **additional
accounts** are listed below. Hovering the active account reveals **Sign out**; clicking any additional
account switches to it. **Settings / Members** open the combined profile modal, and the surface also
exposes **Add organization**, **Add account**, and **Sign out of all accounts**.

It is the styled Mosaic component composed from the headless `@clerk/headless` popover primitive plus
slot recipes, and inherits the primitive's open/close behavior, focus management, and ARIA wiring. This
first pass is presentational: the parts render from the props on `AccountButtonRoot` (mock data in the
examples). A `useAccountButtonController()` that reads live Clerk resources is a drop-in follow-up.

## Example

<Story
name='Default'
storyModule={AccountButtonStories}
/>

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.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Use the Archetype C documentation structure.

Lead with one short paragraph describing owned state and wired lower-layer pieces, followed by one <Story> whose composition array names each direct dependency. The current multiple-story layout follows neither requirement.

As per path instructions, Archetype C MDX must use a single ownership/composition paragraph followed by one Story with a dependency composition array.

Also applies to: 68-89

🤖 Prompt for 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.

In `@packages/swingset/src/stories/account-button.mdx` around lines 3 - 21,
Restructure the AccountButton MDX documentation into Archetype C format: replace
the current descriptive sections with one short paragraph covering owned state
and the wired lower-layer pieces, then provide exactly one Story. Add a
composition array to that Story listing each direct dependency, including the
headless popover primitive and slot recipes, and remove the current multi-story
layout.

Source: Path instructions

Comment on lines +10 to +14
export const meta: StoryMeta = {
group: 'Components',
title: 'AccountButton',
source: 'packages/ui/src/mosaic/components/account-button.view.tsx',
};

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Wire the stories into the playground knobs.

Set meta.styles to accountButtonRecipe, add the local knobsAsProps cast, and spread the resulting props into each AccountButton. The current stories discard every playground value.

As per path instructions, story functions must cast Record<string, unknown> through knobsAsProps, and Mosaic recipe metadata must be assigned to meta.styles.

Also applies to: 36-112

🤖 Prompt for 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.

In `@packages/swingset/src/stories/account-button.stories.tsx` around lines 10 -
14, Update the AccountButton story metadata to assign accountButtonRecipe to
meta.styles. In each story function, cast the knobs Record<string, unknown>
through knobsAsProps and spread the resulting props into AccountButton so
playground values are applied.

Source: Path instructions

Comment on lines +21 to +85
export interface AccountButtonAccount {
sessionId: string;
userId: string;
name: string;
email: string;
imageUrl?: string;
}

export interface AccountButtonMembership {
kind: 'membership';
organizationId: string;
name: string;
imageUrl?: string;
membersCount?: number;
planLabel?: string;
upgradeable?: boolean;
membershipRequestCount?: number;
}

export interface AccountButtonSuggestion {
kind: 'suggestion';
id: string;
organizationId: string;
name: string;
imageUrl?: string;
status: 'pending' | 'accepted';
}

export interface AccountButtonInvitation {
kind: 'invitation';
id: string;
organizationId: string;
organizationName: string;
imageUrl?: string;
}

export interface AccountButtonData {
status: 'loading' | 'ready';
activeAccount: AccountButtonAccount;
/** `null` => the personal workspace is active. */
activeOrganizationId: string | null;
/** Explicit; do not derive from `memberships.length`. */
hasOrganizations: boolean;
memberships: AccountButtonMembership[];
suggestions: AccountButtonSuggestion[];
invitations: AccountButtonInvitation[];
additionalAccounts: AccountButtonAccount[];
}

/** All optional. An unhandled action hides (or de-activates) the affordance it drives. */
export interface AccountButtonCallbacks {
onSelectOrganization?: (organizationId: string) => void;
onSelectPersonal?: () => void;
onAcceptSuggestion?: (suggestionId: string) => void;
onAcceptInvitation?: (invitationId: string) => void;
onSwitchAccount?: (sessionId: string) => void;
onSignOutSession?: (sessionId: string) => void;
onSignOutAll?: () => void;
onManageOrganization?: () => void;
onManageMembers?: () => void;
onManageAccount?: () => void;
onCreateOrganization?: () => void;
onAddAccount?: () => void;
onUpgrade?: () => void;
}

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.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Complete the public API documentation and return types.

The exported resource, callback, and props contracts—especially onUpgrade—lack customer-facing field semantics, while the four exported components have no explicit return types. Add comprehensive JSDoc and React.JSX.Element annotations, then request Docs-team review.

As per coding guidelines, all public APIs require comprehensive JSDoc and explicit return types. As per path instructions, public JSDoc under packages/** feeds generated Clerk Docs.

Also applies to: 812-839, 841-905

🤖 Prompt for 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.

In `@packages/ui/src/mosaic/components/account-button.view.tsx` around lines 21 -
85, Add comprehensive customer-facing JSDoc to the exported
AccountButtonAccount, AccountButtonMembership, AccountButtonSuggestion,
AccountButtonInvitation, AccountButtonData, AccountButtonCallbacks, and props
contracts, documenting field semantics including onUpgrade. Add explicit
React.JSX.Element return types to all four exported AccountButton components,
then request Docs-team review for the generated public API documentation.

Sources: Coding guidelines, Path instructions

Comment on lines +57 to +68
export interface AccountButtonData {
status: 'loading' | 'ready';
activeAccount: AccountButtonAccount;
/** `null` => the personal workspace is active. */
activeOrganizationId: string | null;
/** Explicit; do not derive from `memberships.length`. */
hasOrganizations: boolean;
memberships: AccountButtonMembership[];
suggestions: AccountButtonSuggestion[];
invitations: AccountButtonInvitation[];
additionalAccounts: AccountButtonAccount[];
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not publish an inert status state.

status='loading' renders the complete ready UI and still requires every ready-state resource. Remove status for v1, or make AccountButtonData a real discriminated union with a loading rendering path; correcting this after release would constrain @clerk/ui compatibility.

As per coding guidelines, use discriminated unions for state management and keep packages/ui APIs backwards-compatible.

🤖 Prompt for 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.

In `@packages/ui/src/mosaic/components/account-button.view.tsx` around lines 57 -
68, Remove the inert status field from AccountButtonData for v1, since the
current loading value still requires and renders ready-state data. Update
AccountButton consumers, including the account-button view, to rely on the
existing ready-state shape without status checks; only retain status if you
introduce a genuine discriminated union with a separate loading rendering path.

Source: Coding guidelines

Comment on lines +446 to +808
/>
))}
{data.suggestions.map(s => (
<Row
key={s.id}
shape='square'
name={s.name}
imageUrl={s.imageUrl}
badge={<SuggestedBadge />}
trailing={
acceptSuggestion ? (
<InlineButton
label='Join'
onClick={() => acceptSuggestion(s.id)}
/>
) : undefined
}
/>
))}
{data.invitations.map(i => (
<Row
key={i.id}
shape='square'
name={i.organizationName}
imageUrl={i.imageUrl}
trailing={
acceptInvitation ? (
<InlineButton
label='Accept'
onClick={() => acceptInvitation(i.id)}
/>
) : undefined
}
/>
))}
{data.onCreateOrganization ? (
<AddRow
label='Add organization'
onClick={data.onCreateOrganization}
/>
) : null}
</div>
);
}

function AccountsSection() {
const data = useAccountButtonContext();
const { group, groupLabel } = useRecipe(accountButtonRecipe);
const switchAccount = data.onSwitchAccount;

if (data.additionalAccounts.length === 0 && !data.onAddAccount) {
return null;
}

return (
<div {...group}>
{data.additionalAccounts.length > 0 ? <div {...groupLabel}>Additional accounts</div> : null}
{data.additionalAccounts.map(a => (
<Row
key={a.sessionId}
shape='circle'
name={a.name}
secondary={a.email}
imageUrl={a.imageUrl}
onSelect={switchAccount ? () => switchAccount(a.sessionId) : undefined}
/>
))}
{data.onAddAccount ? (
<AddRow
label='Add account'
onClick={data.onAddAccount}
/>
) : null}
</div>
);
}

function Footer() {
const data = useAccountButtonContext();
const { footer, signOutAll, branding } = useRecipe(accountButtonRecipe);
return (
<div {...footer}>
{data.onSignOutAll ? (
<button
type='button'
onClick={data.onSignOutAll}
{...signOutAll}
>
<Icon
name='sign-out'
size='sm'
sx={t => ({ color: t.color.mutedForeground })}
/>
<span>Sign out of all accounts</span>
</button>
) : null}
<div {...branding}>Secured by Clerk</div>
</div>
);
}

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.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Split the 900-line component into focused modules.

Extract reusable leaves and sections such as Avatar, Row, Header, WorkspaceList, AccountsSection, and Footer. Keep the public compound composition in account-button.view.tsx.

As per coding guidelines, React files should contain one focused component and remain around 150–200 lines.

🤖 Prompt for 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.

In `@packages/ui/src/mosaic/components/account-button.view.tsx` around lines 446 -
808, Split the presentational leaves and sections from account-button.view.tsx
into focused React modules, extracting symbols such as Avatar, Row, Header,
WorkspaceList, AccountsSection, and Footer while preserving their current
behavior and context usage. Keep the public compound component composition and
exports in account-button.view.tsx, and update imports as needed so the file
remains focused and within the project’s preferred component size.

Source: Coding guidelines

Comment on lines +488 to +535
function Row({ name, secondary, shape, imageUrl, onSelect, active, badge, trailing, hoverAction }: RowProps) {
const { item, select, name: nameSlot, secondary: secondarySlot } = useRecipe(accountButtonRecipe);
const inner = (
<>
<Avatar
name={name}
imageUrl={imageUrl}
shape={shape}
size='md'
/>
<span css={{ display: 'flex', flexDirection: 'column', minWidth: 0, flex: 1 }}>
<span css={{ display: 'flex', alignItems: 'center', gap: '0.375rem', minWidth: 0 }}>
<span {...nameSlot}>{name}</span>
{badge}
</span>
{secondary ? <span {...secondarySlot}>{secondary}</span> : null}
</span>
</>
);
return (
<div {...item}>
{onSelect ? (
<button
type='button'
onClick={onSelect}
{...select}
>
{inner}
</button>
) : (
<div
{...select}
style={{ cursor: 'default' }}
>
{inner}
</div>
)}
{active ? (
<Icon
name='check'
size='sm'
sx={t => ({ color: t.color.cardForeground, flexShrink: 0 })}
/>
) : null}
{trailing}
{hoverAction}
</div>
);

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.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Expose the active row to assistive technology.

The check icon is purely visual. Mark the selection control with aria-current so screen-reader users can identify the active account or organization.

Proposed fix
         <button
           type='button'
+          aria-current={active ? 'true' : undefined}
           onClick={onSelect}
           {...select}

As per coding guidelines, React components must implement proper ARIA attributes.

🤖 Prompt for 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.

In `@packages/ui/src/mosaic/components/account-button.view.tsx` around lines 488 -
535, Update the selection control rendered by Row to expose its active state
through the appropriate aria-current attribute, using the active prop’s value.
Apply the attribute to the interactive button and the non-interactive div
consistently, while leaving the visual check icon behavior unchanged.

Source: Coding guidelines

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.

1 participant