fix(ui): self-serve SSO follow-ups (a11y + UX)#8940
Conversation
Changing an SSO provider deletes the existing enterprise connection before creating the new one. Document that this is intentionally non-atomic for the MVP: a failed create briefly leaves the org without a connection, and recovery is by design since the next render revalidates the deleted connection away so a retry becomes a plain create.
…ssible A failed provider change now surfaces the error inline inside the dialog via the shared card state, keeping the dialog open so the user can retry or cancel instead of dropping the error behind a dismissed modal. The dialog also gains an accessible name (aria-labelledby wired to its heading) and restores Escape-to-close (ignored while a change is in progress). Threads aria-labelledby/aria-label and onKeyDown through the Modal primitive onto the role=dialog node.
Replace the role=radio buttons with the established radio-card pattern: a visually hidden native radio inside a label, with the selected and focus styling driven by :has(input:checked) and :has(input:focus-visible). This restores native radiogroup keyboard semantics (arrow-key navigation and roving tabindex) that role=radio on a button drops, while keeping the visible radio dot removed per the design. The radio stays in the accessibility tree (sr-only, not display:none) and names itself from the wrapping label. Also wires the change-provider dialog to own its submit/error state so the step re-throws on failure, and adds coverage for the inline error, Escape-to-close, and the dialog's accessible name.
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
The SSO wizard stepper derived each step's completed tick positionally (sits before the current step), so navigating back un-ticked steps whose work was actually done. Re-entering an already-active connection showed later steps as incomplete depending on where the user stood. Add an optional per-step `isComplete` predicate to the wizard step config, resolved into the stepper's `isCompleted` flag, with the positional value kept as the fallback so wizards that declare no predicate are unchanged. The labeled outer steps now report completion from the same connection flags their guards use, so an active connection shows every step ticked regardless of the current position.
…ity page The security page rendered a wizard-shaped skeleton (stepper + centered spinner + disabled footer) while loading, even though the default view is the overview card. On load this flashed a wizard layout that then popped into a different overview card, and the page "Security" header was missing during load. While loading in the overview view, keep the page chrome stable — the ProfileCard.Page and the "Security" header — and render an overview-shaped placeholder for the SSO section (the section frame with an in-frame spinner) so the settled overview replaces it in place. The wizard skeleton now only renders when loading happens within the wizard view.
…inner Replace the SSO section-framed loading placeholder with a bare spinner centered in the remaining content height beneath the Security header, matching the design. Adds an opt-in sx hook to ProfileCardPage so the overview can fill the scroll box height during load.
Render the Checkmark icon whenever isCompleted, removing the previous !isCurrent guard. A step that is both current and completed now shows the checkmark (on the dark "you are here" background) instead of falling through to its number. Background color precedence is unchanged: isCurrent takes priority over isCompleted, so the bullet stays the dark $colorForeground circle — only the icon inside changes from number to checkmark. Update the navigation test: for a fully active connection all four steps are completed, so all four bullets render checkmarks and zero show a digit (including the current step).
When a step is both current and completed the bullet background is \$colorForeground (light/white in dark mode). The checkmark was always colored \$white, making it invisible. Use \$colorBackground (the inverse) for the current step — the same token the step number already uses — so the check stays readable in both themes.
Linear: ORGS-1666
Description
Follow-up polish to the self-serve SSO change-provider flow (#8881). On this branch:
<button role="radio">, which loses the native radiogroup keyboard contract (arrow-key navigation, roving focus). This returns to a visually-hidden native radio inside the label, keeping the radio dot hidden per design while keyboard a11y works.aria-labelledby, and restores Escape-to-close.changeProvider.Changeset added at wrap-up.
Type of change