Skip to content

fix(react): deprecate SignOutButton signOutOptions prop#8147

Open
jacekradko wants to merge 4 commits intomainfrom
jacek/deprecate-signout-options
Open

fix(react): deprecate SignOutButton signOutOptions prop#8147
jacekradko wants to merge 4 commits intomainfrom
jacek/deprecate-signout-options

Conversation

@jacekradko
Copy link
Member

@jacekradko jacekradko commented Mar 21, 2026

Summary

  • Deprecates the signOutOptions prop on <SignOutButton /> in favor of flat top-level redirectUrl and sessionId props
  • Adds @deprecated JSDoc annotation and runtime deprecation warning via deprecated() helper
  • signOutOptions still works (backwards compatible) but emits a console warning in development

This addresses user feedback about the confusing API where redirectUrl could be passed both as a top-level prop and nested inside signOutOptions.

Related: SDK-17

Test plan

  • New test for top-level sessionId prop
  • Existing signOutOptions test passes unchanged (backwards compat)
  • npx turbo build --filter=@clerk/react passes
  • npx turbo test --filter=@clerk/react passes (396 tests)

Summary by CodeRabbit

  • New Features

    • <SignOutButton /> now accepts sessionId as a top-level prop.
  • Deprecations

    • signOutOptions is deprecated in favor of using redirectUrl and sessionId as separate props; backward compatibility is retained and a deprecation warning is emitted.
  • Tests

    • Added coverage to verify sessionId is passed correctly on sign-out.

@vercel
Copy link

vercel bot commented Mar 21, 2026

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Mar 21, 2026 3:19am

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Mar 21, 2026

🦋 Changeset detected

Latest commit: 99d8b9b

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

This PR includes changesets to release 6 packages
Name Type
@clerk/react Patch
@clerk/chrome-extension Patch
@clerk/expo Patch
@clerk/nextjs Patch
@clerk/react-router Patch
@clerk/tanstack-react-start 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

@github-actions github-actions bot added the react label Mar 21, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 21, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@8147

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@8147

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

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

@clerk/upgrade

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

@clerk/vue

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

commit: 99d8b9b

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2026

📝 Walkthrough

Walkthrough

The pull request deprecates the signOutOptions prop on <SignOutButton /> in @clerk/react and adds an optional top-level sessionId prop alongside redirectUrl. The click handler now always includes redirectUrl, conditionally includes sessionId when provided, and still accepts signOutOptions while emitting a runtime deprecation warning. A new test verifies calling signOut with redirectUrl and sessionId. A Changeset marks a patch bump.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: deprecating the signOutOptions prop on SignOutButton in favor of flatter top-level props.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Tip

CodeRabbit can approve the review once all CodeRabbit's comments are resolved.

Enable the reviews.request_changes_workflow setting to automatically approve the review once all CodeRabbit's comments are resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react/src/components/SignOutButton.tsx`:
- Around line 21-35: The clickHandler in SignOutButton currently spreads
signOutOptions after the explicit redirectUrl/sessionId so nested values can
overwrite top-level props; change the argument to clerk.signOut so
signOutOptions is spread first and then explicit redirectUrl and sessionId are
applied (i.e., spread signOutOptions before adding redirectUrl and the
conditional sessionId) to ensure top-level redirectUrl/sessionId on the
SignOutButton take precedence over deprecated signOutOptions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2a369f34-83d1-4bb9-8cb3-d3c10e7a8ccf

📥 Commits

Reviewing files that changed from the base of the PR and between ac2a349 and 99d8b9b.

📒 Files selected for processing (1)
  • packages/react/src/components/SignOutButton.tsx

Comment on lines +21 to +35
const { redirectUrl = '/', sessionId, signOutOptions, getContainer, component, ...rest } = props;

if (signOutOptions) {
deprecated('SignOutButton `signOutOptions`', 'Use the `redirectUrl` and `sessionId` props directly instead.');
}

children = normalizeWithDefaultValue(children, 'Sign out');
const child = assertSingleChild(children)('SignOutButton');

const clickHandler = () => clerk.signOut({ redirectUrl, ...signOutOptions });
const clickHandler = () =>
clerk.signOut({
redirectUrl,
...(sessionId !== undefined && { sessionId }),
...signOutOptions,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Top-level props lose precedence when both APIs are provided (migration bug)

At Line 34, ...signOutOptions is spread after Line 32-33, so deprecated nested values override top-level redirectUrl/sessionId. That keeps the ambiguous behavior this deprecation is meant to eliminate and can sign out/redirect using the wrong target when consumers pass both during migration.

Proposed fix (preserve backward compatibility, make top-level authoritative)
-    const { redirectUrl = '/', sessionId, signOutOptions, getContainer, component, ...rest } = props;
+    const { redirectUrl, sessionId, signOutOptions, getContainer, component, ...rest } = props;
+
+    const resolvedRedirectUrl = redirectUrl ?? signOutOptions?.redirectUrl ?? '/';
+    const resolvedSessionId = sessionId ?? signOutOptions?.sessionId;

@@
     const clickHandler = () =>
       clerk.signOut({
-        redirectUrl,
-        ...(sessionId !== undefined && { sessionId }),
-        ...signOutOptions,
+        redirectUrl: resolvedRedirectUrl,
+        ...(resolvedSessionId !== undefined && { sessionId: resolvedSessionId }),
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/src/components/SignOutButton.tsx` around lines 21 - 35, The
clickHandler in SignOutButton currently spreads signOutOptions after the
explicit redirectUrl/sessionId so nested values can overwrite top-level props;
change the argument to clerk.signOut so signOutOptions is spread first and then
explicit redirectUrl and sessionId are applied (i.e., spread signOutOptions
before adding redirectUrl and the conditional sessionId) to ensure top-level
redirectUrl/sessionId on the SignOutButton take precedence over deprecated
signOutOptions.

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