Skip to content

Add hosted navigation SPI for framework integrations#519

Draft
mikepitre wants to merge 1 commit into
mainfrom
mike/hosted-navigation
Draft

Add hosted navigation SPI for framework integrations#519
mikepitre wants to merge 1 commit into
mainfrom
mike/hosted-navigation

Conversation

@mikepitre

@mikepitre mikepitre commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

Expo (and any host that embeds our components in its own navigation) can't push UserProfileView onto its stack without getting two headers: the host's route header and Clerk's navigation bar. Hiding our bar alone isn't enough — the host's back button then pops the route while Clerk's internal stack still has screens on it. Context: Slack thread.

What this adds

A @_spi(FrameworkIntegration) environment value, clerkHostedNavigation. When a host sets it:

  • UserProfileView and AuthView hide their navigation bars (iOS only). For the profile that's the whole story — hosts use the existing public navigationPath: initializer, own the NavigationPath, and derive depth / pop from it directly.
  • AuthView's path is an internal [Destination] array that can't be owned externally, so it additionally reports depth changes through onDepthChange and executes pop() / popToRoot() from the handle.

No title reporting: the host owns its header and sets whatever title it wants.

When the environment value is absent (every non-SPI consumer), the components take the same code paths as before. No public API changes.

The add-account sheet inside the profile explicitly resets the environment value so modal auth keeps Clerk's own chrome.

Touch surface

  • HostedNavigation.swift (new, SPI-only): the handle, env entry, and bar-hiding modifier
  • UserProfileView.swift: +6 lines (bar-hiding modifiers at the destination sites, sheet env reset)
  • AuthView.swift: +20 lines (depth reporting + pop handler)

Testing

  • make test-ui: 76 tests in 9 suites pass on iOS simulator, including the new HostedNavigationTests
  • swift build (macOS), make format-check, make lint all clean

The consuming side is clerk/javascript#9121, which needs this in a release before its iOS pod compiles.

🤖 Generated with Claude Code

Hosts that embed UserProfileView or AuthView inside their own navigation
chrome (e.g. the Expo SDK) can now hide Clerk's navigation bars and drive
the components' internal stacks. Setting the new @_spi(FrameworkIntegration)
ClerkHostedNavigation value in the environment hides the bars; AuthView
additionally reports stack depth changes and executes pop()/popToRoot(),
since unlike UserProfileView its path cannot be owned externally.

Behavior is unchanged when the environment value is absent.
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

CI paused

CI does not run automatically on pull request updates.

Before merging, manual CI must be run and pass for the latest commit.

When this PR is ready for CI, the PR author or a repository maintainer can comment:

/run ci

Or use the quick action below:

  • Run CI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant