Skip to content

feat(ui): formalize the Mosaic Profile surface and add a Drawer - #9652

Draft
maxyinger wants to merge 19 commits into
mainfrom
max/profile-component
Draft

feat(ui): formalize the Mosaic Profile surface and add a Drawer#9652
maxyinger wants to merge 19 commits into
mainfrom
max/profile-component

Conversation

@maxyinger

Copy link
Copy Markdown
Collaborator

Description

Formalizes the user page's ad-hoc sidebar/container into a generic Mosaic Profile surface, shared by the user profile and, later, the organization profile and their merge. Direction check-in, not review-ready.

Profile (components/profile/): Root / Nav / NavItem / PageTitle / Content / Page. Compositional internally; UserProfileView is the prop-driven shell on top (activePage, pages, customPages, pageOrder, onPageChange), with the derivation in user-profile.layout.ts. Fixed height standalone and inline (45rem), full-screen on a phone, filled by the popup in a modal. The dialog size panel is renamed profile, with card parity: the popup positions, the surface paints.

Compact navigation: below 48rem of its own width the tablist leaves the column for a bottom sheet. Profile.PageTitle (the h3 every page renders) becomes the trigger — <h3><button>Account ⌄</button></h3> — with the caret vertical-align: middle, so it centres on the x-height. Width is measured on the root rather than queried, since where the one tablist renders is a DOM decision.

Drawer (components/drawer/): the first styled consumer of the headless drawer. Prompt's surface, flush sides and bottom, --cl-radius-2xl top corners, grip, bottom bleed for the rubber band, motion composed from the headless vars, nested scrim inside a modal dialog.

Also: Branding hoisted out of Card and shared; --cl-shadow-card token consumed by Card and the profile frame; ids are apiKeys; custom-page types moved to user-profile.types.ts.

Headless fixes:

  • useRender emits state attributes before other props. Chrome flushes style on a tabindex write to the focused element, and data-selected landing after it left a CSS anchor with nothing to anchor to for one recalc, so a [data-selected]-anchored mark only transitioned in one direction.
  • Drawer drag: the inner-scroll walk stops at the document (a scrolled page vetoed every drag); upward drags at rest rubber-band unless inner content can scroll; swipe vars are mirrored onto the backdrop; a release reaching only window ends the gesture, and closing resets it.

Swingset: Profile and Drawer pages (with a Customized example of CSS-only anchor-positioned selected/hover marks), user-page renamed user-profile.

Austin's #9508 organization rough-in will be rebuilt on Profile rather than rebased.

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:

🤖 Generated with Claude Code

https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx

Replaces the ad-hoc ProfilePage with a generic `Profile` component
(Root / Nav / NavItem / PageTitle / Content / Page), adopted by the user
profile as `UserProfileView` with custom pages and ordering. Renames the
dialog size `panel` to `profile`, hoists the Clerk branding into a shared
`Branding` component, and adds a `--cl-radius-2xl` and `--cl-shadow-card`
token.

Adds a styled `Drawer` (bottom sheet) on the headless primitive. Compact,
the profile's navigation moves into it, opened from each page's headline.

Headless fixes found along the way: `useRender` emits state attributes
before other props so a CSS anchor on `[data-selected]` transitions in
both directions; the drawer's drag gate no longer reads a scrolled page
as inner scroll, rubber-bands upward drags at rest, mirrors its swipe
vars onto the backdrop, and can no longer be left mid-gesture by a lost
release.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
swingset Ready Ready Preview Sep 3, 2026 11:13pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
clerk-js-sandbox Skipped Skipped Sep 3, 2026 11:13pm UTC

Request Review

@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5e24fef

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

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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

`Profile.Title` replaces the `label` prop: a visually hidden heading that
names the navigation, the compact sheet, and the dialog the profile opens
in. The content's clip edge sits 8px inside the frame rather than 16px.

Swingset: the drawer's "inside a profile" example is the real user
profile, and the user profile story gains an overlay example.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
Standalone and inline the frame is its border alone; the card shadow
belongs to the profile dialog.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
…ull sheet 3rem short

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
maxyinger and others added 2 commits September 3, 2026 16:53
# Conflicts:
#	packages/swingset/src/lib/registry.ts
@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/electron

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

@clerk/electron-passkeys

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

@clerk/eslint-plugin

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

@clerk/expo

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

@clerk/expo-google-signin

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

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

@clerk/upgrade

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

@clerk/vue

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

commit: 5e24fef

…dden attribute

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
…n example

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
@vercel
vercel Bot temporarily deployed to Preview – clerk-js-sandbox September 3, 2026 23:08 Inactive
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzajPkZEavBH31fpxG7sx
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