From 8225f3c7e67c7600caf78253c7821868a1707c0d Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 30 Sep 2025 15:23:23 -0600 Subject: [PATCH 01/14] Initial setup --- docs/reference/hooks/use-auth.mdx | 86 ++++++++++++++++++++++++++++ docs/reference/hooks/use-sign-in.mdx | 46 +++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index c3a88e0313..93835fa0e9 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -5,3 +5,89 @@ sdk: astro, chrome-extension, expo, nextjs, react, react-router, remix, tanstack --- + +## Example + +The following example demonstrates how to use the `useAuth()` hook to access the current auth state, like whether the user is signed in or not. It also includes a basic example for using the `getToken()` method to retrieve a session token for fetching data from an external resource. + + + ```tsx {{ filename: 'src/pages/ExternalDataPage.tsx' }} + import { useAuth } from '@clerk/clerk-react' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/external-data/page.tsx' }} + 'use client'; + + import { useAuth } from '@clerk/nextjs'; + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth(); + + const fetchExternalData = async () => { + const token = await getToken(); + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + return response.json(); + }; + + if (!isLoaded) { + return
Loading...
; + } + + if (!isSignedIn) { + return
Sign in to view this page
; + } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ); + } + ``` +
\ No newline at end of file diff --git a/docs/reference/hooks/use-sign-in.mdx b/docs/reference/hooks/use-sign-in.mdx index bddec03f46..dc1d3cbeae 100644 --- a/docs/reference/hooks/use-sign-in.mdx +++ b/docs/reference/hooks/use-sign-in.mdx @@ -5,3 +5,49 @@ sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react- --- + +## Examples + +### Check the current state of a sign-in + +The following example uses the `useSignIn()` hook to access the [`SignIn`](/docs/reference/javascript/sign-in) object, which contains the current sign-in attempt status and methods to create a new sign-in attempt. The `isLoaded` property is used to handle the loading state. + + + ```tsx {{ filename: 'src/pages/SignInPage.tsx' }} + import { useSignIn } from '@clerk/clerk-react' + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-in attempt status is {signIn?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/sign-in/page.tsx' }} + 'use client'; + + import { useSignIn } from '@clerk/nextjs'; + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn(); + + if (!isLoaded) { + // Handle loading state + return null; + } + + return
The current sign-in attempt status is {signIn?.status}.
; + } + ``` +
+ +### Create a custom sign-in flow with `useSignIn()` + +The `useSignIn()` hook can also be used to build fully custom sign-in flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-in flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignIn()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). \ No newline at end of file From 2ba89b45d463c11ea2b8d28855070c85683ab854 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Tue, 30 Sep 2025 16:18:54 -0600 Subject: [PATCH 02/14] Fix linting --- docs/reference/hooks/use-auth.mdx | 94 ++++++++++++++-------------- docs/reference/hooks/use-sign-in.mdx | 34 +++++----- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index 93835fa0e9..cb1bc16387 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -11,33 +11,33 @@ sdk: astro, chrome-extension, expo, nextjs, react, react-router, remix, tanstack The following example demonstrates how to use the `useAuth()` hook to access the current auth state, like whether the user is signed in or not. It also includes a basic example for using the `getToken()` method to retrieve a session token for fetching data from an external resource. - ```tsx {{ filename: 'src/pages/ExternalDataPage.tsx' }} + ```tsx {{ filename: 'src/pages/ExternalDataPage.tsx' }} import { useAuth } from '@clerk/clerk-react' - + export default function ExternalDataPage() { const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() - + const fetchExternalData = async () => { const token = await getToken() - + // Fetch data from an external API const response = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${token}`, }, }) - + return response.json() } - + if (!isLoaded) { return
Loading...
} - + if (!isSignedIn) { return
Sign in to view this page
} - + return (

@@ -51,43 +51,43 @@ The following example demonstrates how to use the `useAuth()` hook to access the - ```tsx {{ filename: 'app/external-data/page.tsx' }} - 'use client'; - - import { useAuth } from '@clerk/nextjs'; - - export default function ExternalDataPage() { - const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth(); - - const fetchExternalData = async () => { - const token = await getToken(); - - // Fetch data from an external API - const response = await fetch('https://api.example.com/data', { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - - return response.json(); - }; - - if (!isLoaded) { - return

Loading...
; - } - - if (!isSignedIn) { - return
Sign in to view this page
; - } - - return ( -
-

- Hello, {userId}! Your current active session is {sessionId}. -

- -
- ); + ```tsx {{ filename: 'app/external-data/page.tsx' }} + 'use client' + + import { useAuth } from '@clerk/nextjs' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
} - ``` - \ No newline at end of file + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` + diff --git a/docs/reference/hooks/use-sign-in.mdx b/docs/reference/hooks/use-sign-in.mdx index dc1d3cbeae..5208ad6dcc 100644 --- a/docs/reference/hooks/use-sign-in.mdx +++ b/docs/reference/hooks/use-sign-in.mdx @@ -13,41 +13,41 @@ sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react- The following example uses the `useSignIn()` hook to access the [`SignIn`](/docs/reference/javascript/sign-in) object, which contains the current sign-in attempt status and methods to create a new sign-in attempt. The `isLoaded` property is used to handle the loading state. - ```tsx {{ filename: 'src/pages/SignInPage.tsx' }} + ```tsx {{ filename: 'src/pages/SignInPage.tsx' }} import { useSignIn } from '@clerk/clerk-react' - + export default function SignInPage() { const { isLoaded, signIn } = useSignIn() - + if (!isLoaded) { // Handle loading state return null } - + return
The current sign-in attempt status is {signIn?.status}.
} ```
- ```tsx {{ filename: 'app/sign-in/page.tsx' }} - 'use client'; + ```tsx {{ filename: 'app/sign-in/page.tsx' }} + 'use client' - import { useSignIn } from '@clerk/nextjs'; + import { useSignIn } from '@clerk/nextjs' - export default function SignInPage() { - const { isLoaded, signIn } = useSignIn(); + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() - if (!isLoaded) { - // Handle loading state - return null; - } + if (!isLoaded) { + // Handle loading state + return null + } - return
The current sign-in attempt status is {signIn?.status}.
; - } - ``` + return
The current sign-in attempt status is {signIn?.status}.
+ } + ```
### Create a custom sign-in flow with `useSignIn()` -The `useSignIn()` hook can also be used to build fully custom sign-in flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-in flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignIn()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). \ No newline at end of file +The `useSignIn()` hook can also be used to build fully custom sign-in flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-in flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignIn()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). From f3aad9167a178f2dbfc911925c1032f829ba4e79 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 1 Oct 2025 12:29:07 -0600 Subject: [PATCH 03/14] More testing --- docs/reference/hooks/use-auth.mdx | 21 +++ docs/reference/hooks/use-reverification.mdx | 48 +---- docs/reference/hooks/use-session.mdx | 199 +++++++++++++++++++- 3 files changed, 223 insertions(+), 45 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index cb1bc16387..4945059e56 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -4,12 +4,24 @@ description: Access and manage authentication state in your application with Cle sdk: astro, chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- +<<<<<<< Updated upstream +======= +The `useAuth()` hook provides access to the current user's authentication state and methods to manage the active session. + +> [!NOTE] +> To access auth data server-side, see the [`Auth` object reference doc](/docs/reference/backend/types/auth-object). + + + By default, Next.js opts all routes into static rendering. If you need to opt a route or routes into dynamic rendering because you need to access the authentication data at request time, you can create a boundary by passing the `dynamic` prop to ``. See the [guide on rendering modes](/docs/guides/development/rendering-modes) for more information, including code examples. + +>>>>>>> Stashed changes ## Example The following example demonstrates how to use the `useAuth()` hook to access the current auth state, like whether the user is signed in or not. It also includes a basic example for using the `getToken()` method to retrieve a session token for fetching data from an external resource. +<<<<<<< Updated upstream ```tsx {{ filename: 'src/pages/ExternalDataPage.tsx' }} import { useAuth } from '@clerk/clerk-react' @@ -91,3 +103,12 @@ The following example demonstrates how to use the `useAuth()` hook to access the } ``` +======= +## Returns + + + +## Parameters + +{/* */} +>>>>>>> Stashed changes diff --git a/docs/reference/hooks/use-reverification.mdx b/docs/reference/hooks/use-reverification.mdx index 7f72bae3c2..1e44e87857 100644 --- a/docs/reference/hooks/use-reverification.mdx +++ b/docs/reference/hooks/use-reverification.mdx @@ -14,59 +14,19 @@ When using reverification, a user's credentials are valid for 10 minutes. Once s ## Parameters - - - `fetcher` - - `Fetcher extends (...args: any[]) => Promise` - - A function that returns a promise. - - --- - - - `options?` - - [`UseReverificationOptions`](#use-reverification-options) - - The optional options object. - + ### `UseReverificationOptions` - - - `onNeedsReverification?` - - (\{ complete, cancel, level }: [NeedsReverificationParameters](#needs-reverification-parameters)) => void - - Handler for the reverification process. Opts out of using the default UI. Use this to build a custom UI. - + ### `NeedsReverificationParameters` - - - `complete` - - `() => void` - - Marks the reverification process as complete and retries the original request. - - --- - - - `cancel` - - `() => void` - - Marks the reverification process as cancelled and rejects the original request. - - --- - - - `level` - - `"first_factor" | "second_factor" | "multi_factor" | undefined` - - The verification level required for the reverification process. - + ## Returns - - - `(...args: any[]) => Promise` - - The action returns the response from the fetcher function. - + ## Examples diff --git a/docs/reference/hooks/use-session.mdx b/docs/reference/hooks/use-session.mdx index 93af5b99cc..750ba49756 100644 --- a/docs/reference/hooks/use-session.mdx +++ b/docs/reference/hooks/use-session.mdx @@ -4,4 +4,201 @@ description: Access and manage the current user's session in your React applicat sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- - +The `useSession()` hook provides access to the current user's [`Session`](https://clerk.com/docs/reference/javascript/session) object, as well as helpers for setting the active session. + +## Returns + + + +## Example + +### Access the `Session` object + +The following example uses the `useSession()` hook to access the `Session` object, which has the `lastActiveAt` property. The `lastActiveAt` property is a `Date` object used to show the time the session was last active. + + + ```tsx {{ filename: 'src/Home.tsx' }} + import { useSession } from '@clerk/clerk-react' + + export default function Home() { + const { isLoaded, session, isSignedIn } = useSession() + + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ) + } + ``` +
+ + +```tsx {{ filename: 'app/page.tsx' }} +'use client'; + +import { useSession } from '@clerk/nextjs'; + +export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession(); + + if (!isLoaded) { + // Handle loading state + return null; + } + if (!isSignedIn) { + // Handle signed out state + return null; + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ); +} +``` +
+ + +```tsx {{ filename: 'app/page.tsx' }} +'use client'; + +import { useSession } from '@clerk/nextjs'; + +export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession(); + + if (!isLoaded) { + // Handle loading state + return null; + } + if (!isSignedIn) { + // Handle signed out state + return null; + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ); +} +``` +
+ + +```tsx {{ filename: 'app/page.tsx' }} +'use client'; + +import { useSession } from '@clerk/nextjs'; + +export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession(); + + if (!isLoaded) { + // Handle loading state + return null; + } + if (!isSignedIn) { + // Handle signed out state + return null; + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ); +} +``` +
+ + +```tsx {{ filename: 'app/page.tsx' }} +'use client'; + +import { useSession } from '@clerk/nextjs'; + +export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession(); + + if (!isLoaded) { + // Handle loading state + return null; + } + if (!isSignedIn) { + // Handle signed out state + return null; + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ); +} +``` +
+ + +```tsx {{ filename: 'app/page.tsx' }} +'use client'; + +import { useSession } from '@clerk/nextjs'; + +export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession(); + + if (!isLoaded) { + // Handle loading state + return null; + } + if (!isSignedIn) { + // Handle signed out state + return null; + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ); +} +``` +
+ + +```tsx {{ filename: 'app/page.tsx' }} +'use client'; + +import { useSession } from '@clerk/nextjs'; + +export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession(); + + if (!isLoaded) { + // Handle loading state + return null; + } + if (!isSignedIn) { + // Handle signed out state + return null; + } + + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ); +} +``` +
From f39f98223bf357148480f2a49870cdd17da639b0 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 1 Oct 2025 14:01:02 -0600 Subject: [PATCH 04/14] Add other hooks --- docs/reference/hooks/use-auth.mdx | 92 +-------- docs/reference/hooks/use-session.mdx | 268 ++++++++++++++------------- docs/reference/hooks/use-sign-in.mdx | 6 +- docs/reference/hooks/use-sign-up.mdx | 52 +++++- docs/reference/hooks/use-user.mdx | 211 ++++++++++++++++++++- 5 files changed, 405 insertions(+), 224 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index 4945059e56..951a345bbd 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -4,111 +4,23 @@ description: Access and manage authentication state in your application with Cle sdk: astro, chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- -<<<<<<< Updated upstream - -======= The `useAuth()` hook provides access to the current user's authentication state and methods to manage the active session. > [!NOTE] > To access auth data server-side, see the [`Auth` object reference doc](/docs/reference/backend/types/auth-object). - By default, Next.js opts all routes into static rendering. If you need to opt a route or routes into dynamic rendering because you need to access the authentication data at request time, you can create a boundary by passing the `dynamic` prop to ``. See the [guide on rendering modes](/docs/guides/development/rendering-modes) for more information, including code examples. + By default, Next.js opts all routes into static rendering. If you need to opt a route or routes into dynamic rendering because you need to access the authentication data at request time, you can create a boundary by passing the `dynamic` prop to ``. See the [guide on rendering modes](/docs/guides/development/rendering-modes) for more information, including code examples. ->>>>>>> Stashed changes ## Example The following example demonstrates how to use the `useAuth()` hook to access the current auth state, like whether the user is signed in or not. It also includes a basic example for using the `getToken()` method to retrieve a session token for fetching data from an external resource. -<<<<<<< Updated upstream - - ```tsx {{ filename: 'src/pages/ExternalDataPage.tsx' }} - import { useAuth } from '@clerk/clerk-react' - - export default function ExternalDataPage() { - const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() - - const fetchExternalData = async () => { - const token = await getToken() - - // Fetch data from an external API - const response = await fetch('https://api.example.com/data', { - headers: { - Authorization: `Bearer ${token}`, - }, - }) - - return response.json() - } - - if (!isLoaded) { - return
Loading...
- } - - if (!isSignedIn) { - return
Sign in to view this page
- } - - return ( -
-

- Hello, {userId}! Your current active session is {sessionId}. -

- -
- ) - } - ``` -
- - - ```tsx {{ filename: 'app/external-data/page.tsx' }} - 'use client' - - import { useAuth } from '@clerk/nextjs' - - export default function ExternalDataPage() { - const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() - - const fetchExternalData = async () => { - const token = await getToken() - - // Fetch data from an external API - const response = await fetch('https://api.example.com/data', { - headers: { - Authorization: `Bearer ${token}`, - }, - }) - - return response.json() - } - - if (!isLoaded) { - return
Loading...
- } - - if (!isSignedIn) { - return
Sign in to view this page
- } - - return ( -
-

- Hello, {userId}! Your current active session is {sessionId}. -

- -
- ) - } - ``` -
-======= ## Returns ## Parameters -{/* */} ->>>>>>> Stashed changes + diff --git a/docs/reference/hooks/use-session.mdx b/docs/reference/hooks/use-session.mdx index 750ba49756..2fe285da83 100644 --- a/docs/reference/hooks/use-session.mdx +++ b/docs/reference/hooks/use-session.mdx @@ -4,7 +4,7 @@ description: Access and manage the current user's session in your React applicat sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- -The `useSession()` hook provides access to the current user's [`Session`](https://clerk.com/docs/reference/javascript/session) object, as well as helpers for setting the active session. +The `useSession()` hook provides access to the current user's [`Session`](/docs/reference/javascript/session) object, as well as helpers for setting the active session. ## Returns @@ -17,12 +17,12 @@ The `useSession()` hook provides access to the current user's [`Session`](https: The following example uses the `useSession()` hook to access the `Session` object, which has the `lastActiveAt` property. The `lastActiveAt` property is a `Date` object used to show the time the session was last active. - ```tsx {{ filename: 'src/Home.tsx' }} + ```tsx {{ filename: 'src/Home.tsx' }} import { useSession } from '@clerk/clerk-react' - + export default function Home() { const { isLoaded, session, isSignedIn } = useSession() - + if (!isLoaded) { // Handle loading state return null @@ -31,7 +31,7 @@ The following example uses the `useSession()` hook to access the `Session` objec // Handle signed out state return null } - + return (

This session has been active since {session.lastActiveAt.toLocaleString()}

@@ -41,164 +41,170 @@ The following example uses the `useSession()` hook to access the `Session` objec ``` - -```tsx {{ filename: 'app/page.tsx' }} -'use client'; + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' -import { useSession } from '@clerk/nextjs'; + import { useSession } from '@clerk/nextjs' -export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession(); + export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession() - if (!isLoaded) { - // Handle loading state - return null; - } - if (!isSignedIn) { - // Handle signed out state - return null; - } + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ); -} -``` + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ) + } + ```
- -```tsx {{ filename: 'app/page.tsx' }} -'use client'; + + ```tsx {{ filename: 'app/routes/page.tsx' }} + 'use client' -import { useSession } from '@clerk/nextjs'; + import { useSession } from '@clerk/react-router' -export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession(); + export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession() - if (!isLoaded) { - // Handle loading state - return null; - } - if (!isSignedIn) { - // Handle signed out state - return null; - } + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ); -} -``` + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ) + } + ```
- -```tsx {{ filename: 'app/page.tsx' }} -'use client'; + + ```tsx {{ filename: 'app/routes/page.tsx' }} + 'use client' -import { useSession } from '@clerk/nextjs'; + import { useSession } from '@clerk/chrome-extension' -export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession(); + export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession() - if (!isLoaded) { - // Handle loading state - return null; - } - if (!isSignedIn) { - // Handle signed out state - return null; - } + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ); -} -``` + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ) + } + ```
- -```tsx {{ filename: 'app/page.tsx' }} -'use client'; + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' -import { useSession } from '@clerk/nextjs'; + import { useSession } from '@clerk/remix' -export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession(); + export default function HomePage() { + const { isLoaded, session, isSignedIn } = useSession() - if (!isLoaded) { - // Handle loading state - return null; - } - if (!isSignedIn) { - // Handle signed out state - return null; - } + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ); -} -``` + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ) + } + ```
- -```tsx {{ filename: 'app/page.tsx' }} -'use client'; + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' -import { useSession } from '@clerk/nextjs'; + import { useSession } from '@clerk/tanstack-react-start' + import { createFileRoute } from '@tanstack/react-router' -export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession(); + export const Route = createFileRoute('/')({ + component: HomePage, + }) - if (!isLoaded) { - // Handle loading state - return null; - } - if (!isSignedIn) { - // Handle signed out state - return null; - } + function HomePage() { + const { isLoaded, session, isSignedIn } = useSession() + + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ); -} -``` + return ( +
+

This session has been active since {session.lastActiveAt.toLocaleString()}

+
+ ) + } + ```
- -```tsx {{ filename: 'app/page.tsx' }} -'use client'; + + ```tsx {{ filename: 'app/routes/page.tsx' }} + 'use client' -import { useSession } from '@clerk/nextjs'; + import { useSession } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' -export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession(); + export function HomePage() { + const { isLoaded, session, isSignedIn } = useSession() - if (!isLoaded) { - // Handle loading state - return null; - } - if (!isSignedIn) { - // Handle signed out state - return null; - } + if (!isLoaded) { + // Handle loading state + return null + } + if (!isSignedIn) { + // Handle signed out state + return null + } - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ); -} -``` + return ( + + This session has been active since {session.lastActiveAt.toLocaleString()} + + ) + } + ```
diff --git a/docs/reference/hooks/use-sign-in.mdx b/docs/reference/hooks/use-sign-in.mdx index 5208ad6dcc..e9ad569e98 100644 --- a/docs/reference/hooks/use-sign-in.mdx +++ b/docs/reference/hooks/use-sign-in.mdx @@ -4,7 +4,11 @@ description: Access and manage the current user's sign-in state in your React ap sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- - +The `useSignIn()` hook provides access to the [`SignIn`](/docs/reference/javascript/sign-in) object, which allows you to check the current state of a sign-in attempt and manage the sign-in flow. You can use this to create a [custom sign-in flow](/docs/guides/development/custom-flows/overview#sign-in-flow). + +## Returns + + ## Examples diff --git a/docs/reference/hooks/use-sign-up.mdx b/docs/reference/hooks/use-sign-up.mdx index e9d38edece..ff5f055df1 100644 --- a/docs/reference/hooks/use-sign-up.mdx +++ b/docs/reference/hooks/use-sign-up.mdx @@ -4,4 +4,54 @@ description: Access and manage the current user's sign-up state in your React ap sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- - +The `useSignUp()` hook provides access to the [`SignUp`](/docs/reference/javascript/sign-up) object, which allows you to check the current state of a sign-up attempt and manage the sign-up flow. You can use this to create a [custom sign-up flow](/docs/guides/development/custom-flows/overview#sign-up-flow). + +## Returns + + + +## Examples + +### Check the current state of a sign-up + +The following example uses the `useSignUp()` hook to access the [`SignUp`](/docs/reference/javascript/sign-up) object, which contains the current sign-up attempt status and methods to create a new sign-up attempt. The `isLoaded` property is used to handle the loading state. + + + ```tsx {{ filename: 'src/pages/SignUpPage.tsx' }} + import { useSignUp } from '@clerk/clerk-react' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/sign-up/page.tsx' }} + 'use client' + + import { useSignUp } from '@clerk/nextjs' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ +### Create a custom sign-up flow with `useSignUp()` + +The `useSignUp()` hook can also be used to build fully custom sign-up flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-up flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignUp()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). diff --git a/docs/reference/hooks/use-user.mdx b/docs/reference/hooks/use-user.mdx index 2322c9d0bd..f3e5d4e4ba 100644 --- a/docs/reference/hooks/use-user.mdx +++ b/docs/reference/hooks/use-user.mdx @@ -4,4 +4,213 @@ description: Access and manage the current user's data in your React application sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- - +The `useUser()` hook provides access to the current user's [`User`](/docs/reference/javascript/user) object, which contains all the data for a single user in your application and provides methods to manage their account. This hook also allows you to check if the user is signed in and if Clerk has loaded and initialized. + +## Returns + + + +## Example + +### Get the current user + +The following example uses the `useUser()` hook to access the [`User`](/docs/reference/javascript/user) object, which contains the current user's data such as their full name. The `isLoaded` and `isSignedIn` properties are used to handle the loading state and to check if the user is signed in, respectively. + + + ```tsx {{ filename: 'src/Example.tsx' }} + import { useUser } from '@clerk/clerk-react' + + export default function Example() { + const { isSignedIn, user, isLoaded } = useUser() + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return
Hello {user.firstName}!
+ } + ``` +
+ + + ```tsx {{ filename: 'app/sign-up/page.tsx' }} + 'use client' + + import { useSignUp } from '@clerk/nextjs' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ +### Update user data + +The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/javascript/user) object, which calls the [`update()`](https://clerk.com/docs/reference/javascript/user#update) method to update the current user's information. + + + ```tsx {{ filename: 'src/Home.tsx' }} + import { useUser } from '@clerk/clerk-react' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' + + import { useUser } from '@clerk/nextjs' + + export default function HomePage() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ +### Reload user data + +The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/javascript/user) object, which calls the [`reload()`](https://clerk.com/docs/reference/javascript/user#reload) method to get the latest user's information. + + + ```tsx {{ filename: 'src/Home.tsx' }} + import { useUser } from '@clerk/clerk-react' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' + + import { useUser } from '@clerk/nextjs' + + export default function HomePage() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
From 7a4340601e591c36334cd02e67b59a028f4fb377 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 1 Oct 2025 14:05:20 -0600 Subject: [PATCH 05/14] Remove testing code --- docs/reference/hooks/use-auth.mdx | 2 +- docs/reference/hooks/use-reverification.mdx | 48 +++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index 951a345bbd..20708db274 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -23,4 +23,4 @@ The following example demonstrates how to use the `useAuth()` hook to access the ## Parameters - +{/* */} diff --git a/docs/reference/hooks/use-reverification.mdx b/docs/reference/hooks/use-reverification.mdx index 1e44e87857..7f72bae3c2 100644 --- a/docs/reference/hooks/use-reverification.mdx +++ b/docs/reference/hooks/use-reverification.mdx @@ -14,19 +14,59 @@ When using reverification, a user's credentials are valid for 10 minutes. Once s ## Parameters - + + - `fetcher` + - `Fetcher extends (...args: any[]) => Promise` + + A function that returns a promise. + + --- + + - `options?` + - [`UseReverificationOptions`](#use-reverification-options) + + The optional options object. + ### `UseReverificationOptions` - + + - `onNeedsReverification?` + - (\{ complete, cancel, level }: [NeedsReverificationParameters](#needs-reverification-parameters)) => void + + Handler for the reverification process. Opts out of using the default UI. Use this to build a custom UI. + ### `NeedsReverificationParameters` - + + - `complete` + - `() => void` + + Marks the reverification process as complete and retries the original request. + + --- + + - `cancel` + - `() => void` + + Marks the reverification process as cancelled and rejects the original request. + + --- + + - `level` + - `"first_factor" | "second_factor" | "multi_factor" | undefined` + + The verification level required for the reverification process. + ## Returns - + + - `(...args: any[]) => Promise` + + The action returns the response from the fetcher function. + ## Examples From d4ca96caea6d9ef9ddb94b97a221d80d9772c39d Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 1 Oct 2025 14:17:25 -0600 Subject: [PATCH 06/14] Add more hooks --- docs/reference/hooks/use-clerk.mdx | 39 +++++++++++++++- docs/reference/hooks/use-session-list.mdx | 56 ++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/docs/reference/hooks/use-clerk.mdx b/docs/reference/hooks/use-clerk.mdx index 26e922f2d2..f0537ee232 100644 --- a/docs/reference/hooks/use-clerk.mdx +++ b/docs/reference/hooks/use-clerk.mdx @@ -4,4 +4,41 @@ description: Access and manage the Clerk object in your React application with C sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- - +> [!WARNING] +> This hook should only be used for advanced use cases, such as building a completely custom OAuth flow or as an escape hatch to access to the `Clerk` object. + +The `useClerk()` hook provides access to the [`Clerk`](/docs/reference/javascript/clerk) object, allowing you to build alternatives to any Clerk Component. + +## Returns + +The `useClerk()` hook returns the `Clerk` object, which includes all the methods and properties listed in the [`Clerk` reference](/docs/reference/javascript/clerk). + +## Example + +The following example uses the `useClerk()` hook to access the `clerk` object. The `clerk` object is used to call the [`openSignIn()`](/docs/reference/javascript/clerk#sign-in) method to open the sign-in modal. + + + ```tsx {{ filename: 'src/Home.tsx' }} + import { useClerk } from '@clerk/clerk-react' + + export default function Home() { + const clerk = useClerk() + + return + } + ``` + + + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' + + import { useClerk } from '@clerk/nextjs' + + export default function HomePage() { + const clerk = useClerk() + + return + } + ``` + diff --git a/docs/reference/hooks/use-session-list.mdx b/docs/reference/hooks/use-session-list.mdx index 5cc504fb2f..9993a5c022 100644 --- a/docs/reference/hooks/use-session-list.mdx +++ b/docs/reference/hooks/use-session-list.mdx @@ -4,4 +4,58 @@ description: Access and manage the current user's session list in your React app sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start --- - +The `useSessionList()` hook returns an array of [`Session`](/docs/reference/javascript/session) objects that have been registered on the client device. + +## Returns + + + +## Example + +### Get a list of sessions + +The following example uses `useSessionList()` to get a list of sessions that have been registered on the client device. The `sessions` property is used to show the number of times the user has visited the page. + + + ```tsx {{ filename: 'src/Home.tsx' }} + import { useSessionList } from '@clerk/clerk-react' + + export default function Home() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( +
+

Welcome back. You've been here {sessions.length} times before.

+
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/page.tsx' }} + 'use client' + + import { useSessionList } from '@clerk/nextjs' + + export default function HomePage() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( +
+

Welcome back. You've been here {sessions.length} times before.

+
+ ) + } + ``` +
From 955a81048fc0aadcb06303127d7c09bce0dce3c8 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 1 Oct 2025 16:32:18 -0600 Subject: [PATCH 07/14] Adds code examples for SDKs --- docs/reference/hooks/use-auth.mdx | 295 +++++++++++++ docs/reference/hooks/use-clerk.mdx | 71 +++- docs/reference/hooks/use-session-list.mdx | 110 ++++- docs/reference/hooks/use-session.mdx | 20 +- docs/reference/hooks/use-sign-in.mdx | 86 ++++ docs/reference/hooks/use-sign-up.mdx | 86 ++++ docs/reference/hooks/use-user.mdx | 477 +++++++++++++++++++++- 7 files changed, 1124 insertions(+), 21 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index 20708db274..fe6a5df73d 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -17,6 +17,301 @@ The `useAuth()` hook provides access to the current user's authentication state The following example demonstrates how to use the `useAuth()` hook to access the current auth state, like whether the user is signed in or not. It also includes a basic example for using the `getToken()` method to retrieve a session token for fetching data from an external resource. + + ```tsx {{ filename: 'src/pages/ExternalDataPage.tsx' }} + import { useAuth } from '@clerk/clerk-react' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/external-data/page.tsx' }} + 'use client' + + import { useAuth } from '@clerk/nextjs' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useAuth } from '@clerk/react-router' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useAuth } from '@clerk/chrome-extension' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useAuth } from '@clerk/remix' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useAuth } from '@clerk/tanstack-react-start' + import { createFileRoute } from '@tanstack/react-router' + + export const Route = createFileRoute('/')({ + component: ExternalDataPage, + }) + + function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( +
+

+ Hello, {userId}! Your current active session is {sessionId}. +

+ +
+ ) + } + ``` +
+ +{/* + + + */} + + + ```tsx {{ filename: 'app/external-data/page.tsx' }} + import { useAuth } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function ExternalDataPage() { + const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() + + const fetchExternalData = async () => { + const token = await getToken() + + // Fetch data from an external API + const response = await fetch('https://api.example.com/data', { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + return response.json() + } + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return ( + + + Hello, {userId}! Your current active session is {sessionId}. + + + Fetch Data + + + ) + } + ``` +
+ ## Returns diff --git a/docs/reference/hooks/use-clerk.mdx b/docs/reference/hooks/use-clerk.mdx index f0537ee232..329e9cca86 100644 --- a/docs/reference/hooks/use-clerk.mdx +++ b/docs/reference/hooks/use-clerk.mdx @@ -18,7 +18,7 @@ The `useClerk()` hook returns the `Clerk` object, which includes all the methods The following example uses the `useClerk()` hook to access the `clerk` object. The `clerk` object is used to call the [`openSignIn()`](/docs/reference/javascript/clerk#sign-in) method to open the sign-in modal. - ```tsx {{ filename: 'src/Home.tsx' }} + ```tsx {{ filename: 'src/pages/Home.tsx' }} import { useClerk } from '@clerk/clerk-react' export default function Home() { @@ -30,7 +30,7 @@ The following example uses the `useClerk()` hook to access the `clerk` object. T - ```tsx {{ filename: 'app/page.tsx' }} + ```tsx {{ filename: 'app/home/page.tsx' }} 'use client' import { useClerk } from '@clerk/nextjs' @@ -42,3 +42,70 @@ The following example uses the `useClerk()` hook to access the `clerk` object. T } ``` + + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useClerk } from '@clerk/react-router' + + export default function Home() { + const clerk = useClerk() + + return + } + ``` + + + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useClerk } from '@clerk/chrome-extension' + + export default function Home() { + const clerk = useClerk() + + return + } + ``` + + + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useClerk } from '@clerk/remix' + + export default function Home() { + const clerk = useClerk() + + return + } + ``` + + + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useClerk } from '@clerk/tanstack-react-start' + + export default function Home() { + const clerk = useClerk() + + return + } + ``` + + + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useClerk } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity } from 'react-native' + + export default function Home() { + const clerk = useClerk() + + return ( + + clerk.openSignIn({})}> + Sign in + + + ) + } + ``` + diff --git a/docs/reference/hooks/use-session-list.mdx b/docs/reference/hooks/use-session-list.mdx index 9993a5c022..f7af0587bc 100644 --- a/docs/reference/hooks/use-session-list.mdx +++ b/docs/reference/hooks/use-session-list.mdx @@ -17,7 +17,7 @@ The `useSessionList()` hook returns an array of [`Session`](/docs/reference/java The following example uses `useSessionList()` to get a list of sessions that have been registered on the client device. The `sessions` property is used to show the number of times the user has visited the page. - ```tsx {{ filename: 'src/Home.tsx' }} + ```tsx {{ filename: 'src/pages/Home.tsx' }} import { useSessionList } from '@clerk/clerk-react' export default function Home() { @@ -38,7 +38,7 @@ The following example uses `useSessionList()` to get a list of sessions that hav - ```tsx {{ filename: 'app/page.tsx' }} + ```tsx {{ filename: 'app/home/page.tsx' }} 'use client' import { useSessionList } from '@clerk/nextjs' @@ -59,3 +59,109 @@ The following example uses `useSessionList()` to get a list of sessions that hav } ``` + + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSessionList } from '@clerk/react-router' + + export default function Home() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( +
+

Welcome back. You've been here {sessions.length} times before.

+
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useSessionList } from '@clerk/chrome-extension' + + export default function Home() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( +
+

Welcome back. You've been here {sessions.length} times before.

+
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSessionList } from '@clerk/remix' + + export default function Home() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( +
+

Welcome back. You've been here {sessions.length} times before.

+
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSessionList } from '@clerk/tanstack-react-start' + + export default function Home() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( +
+

Welcome back. You've been here {sessions.length} times before.

+
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSessionList } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function Home() { + const { isLoaded, sessions } = useSessionList() + + if (!isLoaded) { + // Handle loading state + return null + } + + return ( + + Welcome back. You've been here {sessions.length} times before. + + ) + } + ``` + diff --git a/docs/reference/hooks/use-session.mdx b/docs/reference/hooks/use-session.mdx index 2fe285da83..75f5c616a3 100644 --- a/docs/reference/hooks/use-session.mdx +++ b/docs/reference/hooks/use-session.mdx @@ -17,7 +17,7 @@ The `useSession()` hook provides access to the current user's [`Session`](/docs/ The following example uses the `useSession()` hook to access the `Session` object, which has the `lastActiveAt` property. The `lastActiveAt` property is a `Date` object used to show the time the session was last active. - ```tsx {{ filename: 'src/Home.tsx' }} + ```tsx {{ filename: 'src/pages/Home.tsx' }} import { useSession } from '@clerk/clerk-react' export default function Home() { @@ -42,7 +42,7 @@ The following example uses the `useSession()` hook to access the `Session` objec - ```tsx {{ filename: 'app/page.tsx' }} + ```tsx {{ filename: 'app/home/page.tsx' }} 'use client' import { useSession } from '@clerk/nextjs' @@ -70,8 +70,6 @@ The following example uses the `useSession()` hook to access the `Session` objec ```tsx {{ filename: 'app/routes/page.tsx' }} - 'use client' - import { useSession } from '@clerk/react-router' export default function HomePage() { @@ -96,9 +94,7 @@ The following example uses the `useSession()` hook to access the `Session` objec - ```tsx {{ filename: 'app/routes/page.tsx' }} - 'use client' - + ```tsx {{ filename: 'src/routes/page.tsx' }} import { useSession } from '@clerk/chrome-extension' export default function HomePage() { @@ -123,9 +119,7 @@ The following example uses the `useSession()` hook to access the `Session` objec - ```tsx {{ filename: 'app/page.tsx' }} - 'use client' - + ```tsx {{ filename: 'app/routes/page.tsx' }} import { useSession } from '@clerk/remix' export default function HomePage() { @@ -150,9 +144,7 @@ The following example uses the `useSession()` hook to access the `Session` objec - ```tsx {{ filename: 'app/page.tsx' }} - 'use client' - + ```tsx {{ filename: 'app/routes/page.tsx' }} import { useSession } from '@clerk/tanstack-react-start' import { createFileRoute } from '@tanstack/react-router' @@ -183,8 +175,6 @@ The following example uses the `useSession()` hook to access the `Session` objec ```tsx {{ filename: 'app/routes/page.tsx' }} - 'use client' - import { useSession } from '@clerk/clerk-expo' import { Text, View, TouchableOpacity, ScrollView } from 'react-native' diff --git a/docs/reference/hooks/use-sign-in.mdx b/docs/reference/hooks/use-sign-in.mdx index e9ad569e98..bf00bdaae1 100644 --- a/docs/reference/hooks/use-sign-in.mdx +++ b/docs/reference/hooks/use-sign-in.mdx @@ -52,6 +52,92 @@ The following example uses the `useSignIn()` hook to access the [`SignIn`](/docs ``` + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignIn } from '@clerk/react-router' + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-in attempt status is {signIn?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useSignIn } from '@clerk/chrome-extension' + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-in attempt status is {signIn?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignIn } from '@clerk/remix' + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-in attempt status is {signIn?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignIn } from '@clerk/tanstack-react-start' + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-in attempt status is {signIn?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignIn } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function SignInPage() { + const { isLoaded, signIn } = useSignIn() + + if (!isLoaded) { + // Handle loading state + return null + } + + return The current sign-in attempt status is {signIn?.status}. + } + ``` + + ### Create a custom sign-in flow with `useSignIn()` The `useSignIn()` hook can also be used to build fully custom sign-in flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-in flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignIn()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). diff --git a/docs/reference/hooks/use-sign-up.mdx b/docs/reference/hooks/use-sign-up.mdx index ff5f055df1..ba6957760b 100644 --- a/docs/reference/hooks/use-sign-up.mdx +++ b/docs/reference/hooks/use-sign-up.mdx @@ -52,6 +52,92 @@ The following example uses the `useSignUp()` hook to access the [`SignUp`](/docs ```
+ + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignUp } from '@clerk/react-router' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useSignUp } from '@clerk/chrome-extension' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignUp } from '@clerk/remix' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignUp } from '@clerk/tanstack-react-start' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return
The current sign-up attempt status is {signUp?.status}.
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useSignUp } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function SignUpPage() { + const { isLoaded, signUp } = useSignUp() + + if (!isLoaded) { + // Handle loading state + return null + } + + return The current sign-up attempt status is {signUp?.status}. + } + ``` + + ### Create a custom sign-up flow with `useSignUp()` The `useSignUp()` hook can also be used to build fully custom sign-up flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-up flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignUp()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). diff --git a/docs/reference/hooks/use-user.mdx b/docs/reference/hooks/use-user.mdx index f3e5d4e4ba..af59251215 100644 --- a/docs/reference/hooks/use-user.mdx +++ b/docs/reference/hooks/use-user.mdx @@ -17,10 +17,10 @@ The `useUser()` hook provides access to the current user's [`User`](/docs/refere The following example uses the `useUser()` hook to access the [`User`](/docs/reference/javascript/user) object, which contains the current user's data such as their full name. The `isLoaded` and `isSignedIn` properties are used to handle the loading state and to check if the user is signed in, respectively. - ```tsx {{ filename: 'src/Example.tsx' }} + ```tsx {{ filename: 'src/pages/SignUp.tsx' }} import { useUser } from '@clerk/clerk-react' - export default function Example() { + export default function SignUpPage() { const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { @@ -55,6 +55,107 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref ``` + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/react-router' + + export default function SignUpPage() { + const { isSignedIn, user, isLoaded } = useUser() + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return
Hello {user.firstName}!
+ } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useUser } from '@clerk/chrome-extension' + + export default function SignUpPage() { + const { isSignedIn, user, isLoaded } = useUser() + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return
Hello {user.firstName}!
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/remix' + + export default function SignUpPage() { + const { isSignedIn, user, isLoaded } = useUser() + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return
Hello {user.firstName}!
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/tanstack-react-start' + + export default function SignUpPage() { + const { isSignedIn, user, isLoaded } = useUser() + + if (!isLoaded) { + return
Loading...
+ } + + if (!isSignedIn) { + return
Sign in to view this page
+ } + + return
Hello {user.firstName}!
+ } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function SignUpPage() { + const { isSignedIn, user, isLoaded } = useUser() + + if (!isLoaded) { + return Loading... + } + + if (!isSignedIn) { + return Sign in to view this page + } + + return Hello {user.firstName}! + } + ``` + + ### Update user data The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/javascript/user) object, which calls the [`update()`](https://clerk.com/docs/reference/javascript/user#update) method to update the current user's information. @@ -125,6 +226,167 @@ The following example uses the `useUser()` hook to access the [`User`](https://c ```
+ + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/react-router' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useUser } from '@clerk/chrome-extension' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/remix' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/tanstack-react-start' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + await user.update({ + firstName: 'John', + lastName: 'Doe', + }) + } + + return ( + <> + +

user.firstName: {user.firstName}

+

user.lastName: {user.lastName}

+ + ) + } + ``` +
+ ### Reload user data The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/javascript/user) object, which calls the [`reload()`](https://clerk.com/docs/reference/javascript/user#reload) method to get the latest user's information. @@ -214,3 +476,214 @@ The following example uses the `useUser()` hook to access the [`User`](https://c } ```
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/react-router' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'src/routes/page.tsx' }} + import { useUser } from '@clerk/chrome-extension' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/remix' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/tanstack-react-start' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
+ + + ```tsx {{ filename: 'app/routes/page.tsx' }} + import { useUser } from '@clerk/clerk-expo' + import { Text, View, TouchableOpacity, ScrollView } from 'react-native' + + export default function Home() { + const { isSignedIn, isLoaded, user } = useUser() + + if (!isLoaded) { + // Handle loading state + return null + } + + if (!isSignedIn) return null + + const updateUser = async () => { + // Update data via an API endpoint + const updateMetadata = await fetch('/api/updateMetadata', { + method: 'POST', + body: JSON.stringify({ + role: 'admin', + }), + }) + + // Check if the update was successful + if ((await updateMetadata.json()).message !== 'success') { + throw new Error('Error updating') + } + + // If the update was successful, reload the user data + await user.reload() + } + + return ( + <> + +

user role: {user.publicMetadata.role}

+ + ) + } + ``` +
From cca2ef10dcb460bd1954914931d0ec4a67087e17 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 1 Oct 2025 17:04:09 -0600 Subject: [PATCH 08/14] Remove remix --- docs/reference/hooks/use-auth.mdx | 42 +--------- docs/reference/hooks/use-clerk.mdx | 14 +--- docs/reference/hooks/use-session-list.mdx | 23 +----- docs/reference/hooks/use-session.mdx | 27 +------ docs/reference/hooks/use-sign-in.mdx | 19 +---- docs/reference/hooks/use-sign-up.mdx | 19 +---- docs/reference/hooks/use-user.mdx | 96 +---------------------- 7 files changed, 7 insertions(+), 233 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index fe6a5df73d..7f49fda99d 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -1,7 +1,7 @@ --- title: useAuth() description: Access and manage authentication state in your application with Clerk's useAuth() hook. -sdk: astro, chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: astro, chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- The `useAuth()` hook provides access to the current user's authentication state and methods to manage the active session. @@ -179,46 +179,6 @@ The following example demonstrates how to use the `useAuth()` hook to access the ```
- - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useAuth } from '@clerk/remix' - - export default function ExternalDataPage() { - const { userId, sessionId, getToken, isLoaded, isSignedIn } = useAuth() - - const fetchExternalData = async () => { - const token = await getToken() - - // Fetch data from an external API - const response = await fetch('https://api.example.com/data', { - headers: { - Authorization: `Bearer ${token}`, - }, - }) - - return response.json() - } - - if (!isLoaded) { - return
Loading...
- } - - if (!isSignedIn) { - return
Sign in to view this page
- } - - return ( -
-

- Hello, {userId}! Your current active session is {sessionId}. -

- -
- ) - } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useAuth } from '@clerk/tanstack-react-start' diff --git a/docs/reference/hooks/use-clerk.mdx b/docs/reference/hooks/use-clerk.mdx index 329e9cca86..3012838c65 100644 --- a/docs/reference/hooks/use-clerk.mdx +++ b/docs/reference/hooks/use-clerk.mdx @@ -1,7 +1,7 @@ --- title: useClerk() description: Access and manage the Clerk object in your React application with Clerk's useClerk() hook. -sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- > [!WARNING] @@ -67,18 +67,6 @@ The following example uses the `useClerk()` hook to access the `clerk` object. T ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useClerk } from '@clerk/remix' - - export default function Home() { - const clerk = useClerk() - - return - } - ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} import { useClerk } from '@clerk/tanstack-react-start' diff --git a/docs/reference/hooks/use-session-list.mdx b/docs/reference/hooks/use-session-list.mdx index f7af0587bc..fc675cb2b9 100644 --- a/docs/reference/hooks/use-session-list.mdx +++ b/docs/reference/hooks/use-session-list.mdx @@ -1,7 +1,7 @@ --- title: useSessionList() description: Access and manage the current user's session list in your React application with Clerk's useSessionList() hook. -sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- The `useSessionList()` hook returns an array of [`Session`](/docs/reference/javascript/session) objects that have been registered on the client device. @@ -102,27 +102,6 @@ The following example uses `useSessionList()` to get a list of sessions that hav ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useSessionList } from '@clerk/remix' - - export default function Home() { - const { isLoaded, sessions } = useSessionList() - - if (!isLoaded) { - // Handle loading state - return null - } - - return ( -
-

Welcome back. You've been here {sessions.length} times before.

-
- ) - } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useSessionList } from '@clerk/tanstack-react-start' diff --git a/docs/reference/hooks/use-session.mdx b/docs/reference/hooks/use-session.mdx index 75f5c616a3..e7f2c23f6c 100644 --- a/docs/reference/hooks/use-session.mdx +++ b/docs/reference/hooks/use-session.mdx @@ -1,7 +1,7 @@ --- title: useSession() description: Access and manage the current user's session in your React application with Clerk's useSession() hook. -sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- The `useSession()` hook provides access to the current user's [`Session`](/docs/reference/javascript/session) object, as well as helpers for setting the active session. @@ -118,31 +118,6 @@ The following example uses the `useSession()` hook to access the `Session` objec ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useSession } from '@clerk/remix' - - export default function HomePage() { - const { isLoaded, session, isSignedIn } = useSession() - - if (!isLoaded) { - // Handle loading state - return null - } - if (!isSignedIn) { - // Handle signed out state - return null - } - - return ( -
-

This session has been active since {session.lastActiveAt.toLocaleString()}

-
- ) - } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useSession } from '@clerk/tanstack-react-start' diff --git a/docs/reference/hooks/use-sign-in.mdx b/docs/reference/hooks/use-sign-in.mdx index bf00bdaae1..8b1bb8bcc8 100644 --- a/docs/reference/hooks/use-sign-in.mdx +++ b/docs/reference/hooks/use-sign-in.mdx @@ -1,7 +1,7 @@ --- title: useSignIn() description: Access and manage the current user's sign-in state in your React application with Clerk's useSignIn() hook. -sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- The `useSignIn()` hook provides access to the [`SignIn`](/docs/reference/javascript/sign-in) object, which allows you to check the current state of a sign-in attempt and manage the sign-in flow. You can use this to create a [custom sign-in flow](/docs/guides/development/custom-flows/overview#sign-in-flow). @@ -86,23 +86,6 @@ The following example uses the `useSignIn()` hook to access the [`SignIn`](/docs ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useSignIn } from '@clerk/remix' - - export default function SignInPage() { - const { isLoaded, signIn } = useSignIn() - - if (!isLoaded) { - // Handle loading state - return null - } - - return
The current sign-in attempt status is {signIn?.status}.
- } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useSignIn } from '@clerk/tanstack-react-start' diff --git a/docs/reference/hooks/use-sign-up.mdx b/docs/reference/hooks/use-sign-up.mdx index ba6957760b..bdcea08bf6 100644 --- a/docs/reference/hooks/use-sign-up.mdx +++ b/docs/reference/hooks/use-sign-up.mdx @@ -1,7 +1,7 @@ --- title: useSignUp() description: Access and manage the current user's sign-up state in your React application with Clerk's useSignUp() hook. -sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- The `useSignUp()` hook provides access to the [`SignUp`](/docs/reference/javascript/sign-up) object, which allows you to check the current state of a sign-up attempt and manage the sign-up flow. You can use this to create a [custom sign-up flow](/docs/guides/development/custom-flows/overview#sign-up-flow). @@ -86,23 +86,6 @@ The following example uses the `useSignUp()` hook to access the [`SignUp`](/docs ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useSignUp } from '@clerk/remix' - - export default function SignUpPage() { - const { isLoaded, signUp } = useSignUp() - - if (!isLoaded) { - // Handle loading state - return null - } - - return
The current sign-up attempt status is {signUp?.status}.
- } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useSignUp } from '@clerk/tanstack-react-start' diff --git a/docs/reference/hooks/use-user.mdx b/docs/reference/hooks/use-user.mdx index af59251215..c47225f2ea 100644 --- a/docs/reference/hooks/use-user.mdx +++ b/docs/reference/hooks/use-user.mdx @@ -1,7 +1,7 @@ --- title: useUser() description: Access and manage the current user's data in your React application with Clerk's useUser() hook. -sdk: chrome-extension, expo, nextjs, react, react-router, remix, tanstack-react-start +sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start --- The `useUser()` hook provides access to the current user's [`User`](/docs/reference/javascript/user) object, which contains all the data for a single user in your application and provides methods to manage their account. This hook also allows you to check if the user is signed in and if Clerk has loaded and initialized. @@ -95,26 +95,6 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useUser } from '@clerk/remix' - - export default function SignUpPage() { - const { isSignedIn, user, isLoaded } = useUser() - - if (!isLoaded) { - return
Loading...
- } - - if (!isSignedIn) { - return
Sign in to view this page
- } - - return
Hello {user.firstName}!
- } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useUser } from '@clerk/tanstack-react-start' @@ -290,38 +270,6 @@ The following example uses the `useUser()` hook to access the [`User`](https://c ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useUser } from '@clerk/remix' - - export default function Home() { - const { isSignedIn, isLoaded, user } = useUser() - - if (!isLoaded) { - // Handle loading state - return null - } - - if (!isSignedIn) return null - - const updateUser = async () => { - await user.update({ - firstName: 'John', - lastName: 'Doe', - }) - } - - return ( - <> - -

user.firstName: {user.firstName}

-

user.lastName: {user.lastName}

- - ) - } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useUser } from '@clerk/tanstack-react-start' @@ -561,48 +509,6 @@ The following example uses the `useUser()` hook to access the [`User`](https://c ``` - - ```tsx {{ filename: 'app/routes/page.tsx' }} - import { useUser } from '@clerk/remix' - - export default function Home() { - const { isSignedIn, isLoaded, user } = useUser() - - if (!isLoaded) { - // Handle loading state - return null - } - - if (!isSignedIn) return null - - const updateUser = async () => { - // Update data via an API endpoint - const updateMetadata = await fetch('/api/updateMetadata', { - method: 'POST', - body: JSON.stringify({ - role: 'admin', - }), - }) - - // Check if the update was successful - if ((await updateMetadata.json()).message !== 'success') { - throw new Error('Error updating') - } - - // If the update was successful, reload the user data - await user.reload() - } - - return ( - <> - -

user role: {user.publicMetadata.role}

- - ) - } - ``` -
- ```tsx {{ filename: 'app/routes/page.tsx' }} import { useUser } from '@clerk/tanstack-react-start' From ba4900e1f9e37c4072c3718e0b141799f79450cf Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Thu, 2 Oct 2025 12:36:21 -0600 Subject: [PATCH 09/14] Refinements --- docs/reference/hooks/use-user.mdx | 36 +++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/reference/hooks/use-user.mdx b/docs/reference/hooks/use-user.mdx index c47225f2ea..067862837d 100644 --- a/docs/reference/hooks/use-user.mdx +++ b/docs/reference/hooks/use-user.mdx @@ -17,10 +17,10 @@ The `useUser()` hook provides access to the current user's [`User`](/docs/refere The following example uses the `useUser()` hook to access the [`User`](/docs/reference/javascript/user) object, which contains the current user's data such as their full name. The `isLoaded` and `isSignedIn` properties are used to handle the loading state and to check if the user is signed in, respectively. - ```tsx {{ filename: 'src/pages/SignUp.tsx' }} + ```tsx {{ filename: 'src/pages/Example.tsx' }} import { useUser } from '@clerk/clerk-react' - export default function SignUpPage() { + export default function Example() { const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { @@ -37,20 +37,24 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref - ```tsx {{ filename: 'app/sign-up/page.tsx' }} + ```tsx {{ filename: 'app/example/page.tsx' }} 'use client' - import { useSignUp } from '@clerk/nextjs' + import { useUser } from '@clerk/nextjs' - export default function SignUpPage() { - const { isLoaded, signUp } = useSignUp() + export default function Example() { + const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { // Handle loading state - return null + return
Loading...
} - return
The current sign-up attempt status is {signUp?.status}.
+ if (!isSignedIn) { + return
Sign in to view this page
+ } + + return
Hello {user.firstName}!
} ```
@@ -59,7 +63,7 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref ```tsx {{ filename: 'app/routes/page.tsx' }} import { useUser } from '@clerk/react-router' - export default function SignUpPage() { + export default function Example() { const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { @@ -79,7 +83,7 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref ```tsx {{ filename: 'src/routes/page.tsx' }} import { useUser } from '@clerk/chrome-extension' - export default function SignUpPage() { + export default function Example() { const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { @@ -99,7 +103,7 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref ```tsx {{ filename: 'app/routes/page.tsx' }} import { useUser } from '@clerk/tanstack-react-start' - export default function SignUpPage() { + export default function Example() { const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { @@ -120,7 +124,7 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref import { useUser } from '@clerk/clerk-expo' import { Text, View, TouchableOpacity, ScrollView } from 'react-native' - export default function SignUpPage() { + export default function Example() { const { isSignedIn, user, isLoaded } = useUser() if (!isLoaded) { @@ -138,10 +142,10 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref ### Update user data -The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/javascript/user) object, which calls the [`update()`](https://clerk.com/docs/reference/javascript/user#update) method to update the current user's information. +The following example uses the `useUser()` hook to access the [`User`](/docs/reference/javascript/user) object, which calls the [`update()`](/docs/reference/javascript/user#update) method to update the current user's information. - ```tsx {{ filename: 'src/Home.tsx' }} + ```tsx {{ filename: 'src/pages/Home.tsx' }} import { useUser } from '@clerk/clerk-react' export default function Home() { @@ -337,10 +341,10 @@ The following example uses the `useUser()` hook to access the [`User`](https://c ### Reload user data -The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/javascript/user) object, which calls the [`reload()`](https://clerk.com/docs/reference/javascript/user#reload) method to get the latest user's information. +The following example uses the `useUser()` hook to access the [`User`](/docs/reference/javascript/user) object, which calls the [`reload()`](/docs/reference/javascript/user#reload) method to get the latest user's information. - ```tsx {{ filename: 'src/Home.tsx' }} + ```tsx {{ filename: 'src/pages/Home.tsx' }} import { useUser } from '@clerk/clerk-react' export default function Home() { From d485759f75d350e57daa608b045cb81e874702aa Mon Sep 17 00:00:00 2001 From: Nick Wylynko Date: Mon, 6 Oct 2025 20:33:23 +0800 Subject: [PATCH 10/14] Uncomment the use auth parameters --- docs/reference/hooks/use-auth.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index 7f49fda99d..edcc993eb9 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -272,10 +272,12 @@ The following example demonstrates how to use the `useAuth()` hook to access the ``` +## Parameters + + + ## Returns -## Parameters -{/* */} From b91bc45107cf07470eed1f6af7e29f04678c46d2 Mon Sep 17 00:00:00 2001 From: Nick Wylynko Date: Thu, 9 Oct 2025 01:21:31 +0800 Subject: [PATCH 11/14] switch to new typedocs --- docs/reference/hooks/use-auth.mdx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index edcc993eb9..cf040822f7 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -272,12 +272,8 @@ The following example demonstrates how to use the `useAuth()` hook to access the ``` -## Parameters + - - -## Returns - - + From 368aee11e8171d60d86d6e16a169309643ad982e Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 8 Oct 2025 13:15:52 -0600 Subject: [PATCH 12/14] Replace typedoc return with new location --- docs/reference/hooks/use-clerk.mdx | 6 ++---- docs/reference/hooks/use-session-list.mdx | 6 ++---- docs/reference/hooks/use-session.mdx | 6 ++---- docs/reference/hooks/use-sign-in.mdx | 6 ++---- docs/reference/hooks/use-sign-up.mdx | 6 ++---- docs/reference/hooks/use-user.mdx | 6 ++---- 6 files changed, 12 insertions(+), 24 deletions(-) diff --git a/docs/reference/hooks/use-clerk.mdx b/docs/reference/hooks/use-clerk.mdx index 3012838c65..5221383944 100644 --- a/docs/reference/hooks/use-clerk.mdx +++ b/docs/reference/hooks/use-clerk.mdx @@ -9,10 +9,6 @@ sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start The `useClerk()` hook provides access to the [`Clerk`](/docs/reference/javascript/clerk) object, allowing you to build alternatives to any Clerk Component. -## Returns - -The `useClerk()` hook returns the `Clerk` object, which includes all the methods and properties listed in the [`Clerk` reference](/docs/reference/javascript/clerk). - ## Example The following example uses the `useClerk()` hook to access the `clerk` object. The `clerk` object is used to call the [`openSignIn()`](/docs/reference/javascript/clerk#sign-in) method to open the sign-in modal. @@ -97,3 +93,5 @@ The following example uses the `useClerk()` hook to access the `clerk` object. T } ```
+ + diff --git a/docs/reference/hooks/use-session-list.mdx b/docs/reference/hooks/use-session-list.mdx index fc675cb2b9..a2da5c5ecd 100644 --- a/docs/reference/hooks/use-session-list.mdx +++ b/docs/reference/hooks/use-session-list.mdx @@ -6,10 +6,6 @@ sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start The `useSessionList()` hook returns an array of [`Session`](/docs/reference/javascript/session) objects that have been registered on the client device. -## Returns - - - ## Example ### Get a list of sessions @@ -144,3 +140,5 @@ The following example uses `useSessionList()` to get a list of sessions that hav } ```
+ + diff --git a/docs/reference/hooks/use-session.mdx b/docs/reference/hooks/use-session.mdx index e7f2c23f6c..dc128f4a0a 100644 --- a/docs/reference/hooks/use-session.mdx +++ b/docs/reference/hooks/use-session.mdx @@ -6,10 +6,6 @@ sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start The `useSession()` hook provides access to the current user's [`Session`](/docs/reference/javascript/session) object, as well as helpers for setting the active session. -## Returns - - - ## Example ### Access the `Session` object @@ -173,3 +169,5 @@ The following example uses the `useSession()` hook to access the `Session` objec } ```
+ + diff --git a/docs/reference/hooks/use-sign-in.mdx b/docs/reference/hooks/use-sign-in.mdx index 8b1bb8bcc8..1108833536 100644 --- a/docs/reference/hooks/use-sign-in.mdx +++ b/docs/reference/hooks/use-sign-in.mdx @@ -6,10 +6,6 @@ sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start The `useSignIn()` hook provides access to the [`SignIn`](/docs/reference/javascript/sign-in) object, which allows you to check the current state of a sign-in attempt and manage the sign-in flow. You can use this to create a [custom sign-in flow](/docs/guides/development/custom-flows/overview#sign-in-flow). -## Returns - - - ## Examples ### Check the current state of a sign-in @@ -124,3 +120,5 @@ The following example uses the `useSignIn()` hook to access the [`SignIn`](/docs ### Create a custom sign-in flow with `useSignIn()` The `useSignIn()` hook can also be used to build fully custom sign-in flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-in flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignIn()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). + + diff --git a/docs/reference/hooks/use-sign-up.mdx b/docs/reference/hooks/use-sign-up.mdx index bdcea08bf6..911147d4dc 100644 --- a/docs/reference/hooks/use-sign-up.mdx +++ b/docs/reference/hooks/use-sign-up.mdx @@ -6,10 +6,6 @@ sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start The `useSignUp()` hook provides access to the [`SignUp`](/docs/reference/javascript/sign-up) object, which allows you to check the current state of a sign-up attempt and manage the sign-up flow. You can use this to create a [custom sign-up flow](/docs/guides/development/custom-flows/overview#sign-up-flow). -## Returns - - - ## Examples ### Check the current state of a sign-up @@ -124,3 +120,5 @@ The following example uses the `useSignUp()` hook to access the [`SignUp`](/docs ### Create a custom sign-up flow with `useSignUp()` The `useSignUp()` hook can also be used to build fully custom sign-up flows, if Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow. Different sign-up flows include email and password, email and phone codes, email links, and multifactor (MFA). To learn more about using the `useSignUp()` hook to create custom flows, see the [custom flow guides](/docs/guides/development/custom-flows/overview). + + diff --git a/docs/reference/hooks/use-user.mdx b/docs/reference/hooks/use-user.mdx index 067862837d..c46f668941 100644 --- a/docs/reference/hooks/use-user.mdx +++ b/docs/reference/hooks/use-user.mdx @@ -6,10 +6,6 @@ sdk: chrome-extension, expo, nextjs, react, react-router, tanstack-react-start The `useUser()` hook provides access to the current user's [`User`](/docs/reference/javascript/user) object, which contains all the data for a single user in your application and provides methods to manage their account. This hook also allows you to check if the user is signed in and if Clerk has loaded and initialized. -## Returns - - - ## Example ### Get the current user @@ -597,3 +593,5 @@ The following example uses the `useUser()` hook to access the [`User`](/docs/ref } ```
+ + From 63593e01f700e9a53bd209747d96dc3a64ac3ee6 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 8 Oct 2025 14:40:28 -0600 Subject: [PATCH 13/14] Add code examples billing hooks --- .../billing/add-new-payment-method.mdx | 81 ++++ docs/reference/hooks/use-auth.mdx | 2 - docs/reference/hooks/use-checkout.mdx | 425 ++++++++++++------ docs/reference/hooks/use-payment-attempts.mdx | 349 +++++++++----- docs/reference/hooks/use-payment-methods.mdx | 301 +++++++++---- docs/reference/hooks/use-plans.mdx | 226 +++++++--- docs/reference/hooks/use-statements.mdx | 187 +++++--- docs/reference/hooks/use-subscription.mdx | 424 ++++++++++++----- 8 files changed, 1446 insertions(+), 549 deletions(-) diff --git a/docs/_partials/billing/add-new-payment-method.mdx b/docs/_partials/billing/add-new-payment-method.mdx index 80e5bde2f6..0286b0d868 100644 --- a/docs/_partials/billing/add-new-payment-method.mdx +++ b/docs/_partials/billing/add-new-payment-method.mdx @@ -3,6 +3,7 @@ The following example demonstrates how to create a billing page where a user can - **``**: Sets up the ``, which specifies that the payment actions within its children are `for` the `user`. - **``**: Renders the payment form and handles the submission logic. It uses `usePaymentElement()` to get the `submit` function and `useUser()` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. + ", ""]}> ```tsx {{ filename: 'app/user/billing/page.tsx' }} import { ClerkLoaded } from '@clerk/nextjs' @@ -80,3 +81,83 @@ The following example demonstrates how to create a billing page where a user can } ``` + + + +", ""]}> + ```tsx {{ filename: 'src/user/billing/page.tsx' }} + import { ClerkLoaded } from '@clerk/clerk-react' + import { PaymentElementProvider } from '@clerk/clerk-react/experimental' + import { AddPaymentMethodForm } from './AddPaymentMethodForm' + + export default function Page() { + return ( +
+

Billing Settings

+ + + + + + +
+ ) + } + ``` + + ```tsx {{ filename: 'src/user/billing/AddPaymentMethodForm.tsx' }} + import { useUser } from '@clerk/clerk-react' + import { usePaymentElement, PaymentElement } from '@clerk/clerk-react/experimental' + import { useState } from 'react' + + export function AddPaymentMethodForm() { + const { user } = useUser() + const { submit, isFormReady } = usePaymentElement() + const [isSubmitting, setIsSubmitting] = useState(false) + const [error, setError] = useState(null) + + const handleAddPaymentMethod = async (e: React.FormEvent) => { + e.preventDefault() + if (!isFormReady || !user) { + return + } + + setError(null) + setIsSubmitting(true) + + try { + // 1. Submit the form to the payment provider to get a payment token + const { data, error } = await submit() + + // Usually a validation error from stripe that you can ignore. + if (error) { + setIsSubmitting(false) + return + } + + // 2. Use the token to add the payment source to the user + await user.addPaymentSource(data) + + // 3. Handle success (e.g., show a confirmation, clear the form) + alert('Payment method added successfully!') + } catch (err: any) { + setError(err.message || 'An unexpected error occurred.') + } finally { + setIsSubmitting(false) + } + } + + return ( +
+

Add a new payment method

+ + + {error &&

{error}

} + + ) + } + ``` +
+
\ No newline at end of file diff --git a/docs/reference/hooks/use-auth.mdx b/docs/reference/hooks/use-auth.mdx index cf040822f7..799838c466 100644 --- a/docs/reference/hooks/use-auth.mdx +++ b/docs/reference/hooks/use-auth.mdx @@ -275,5 +275,3 @@ The following example demonstrates how to use the `useAuth()` hook to access the - - diff --git a/docs/reference/hooks/use-checkout.mdx b/docs/reference/hooks/use-checkout.mdx index f6ef42ff76..36a2e8b1fb 100644 --- a/docs/reference/hooks/use-checkout.mdx +++ b/docs/reference/hooks/use-checkout.mdx @@ -198,119 +198,237 @@ The `useCheckout()` hook can be used with a context provider for managing state ", ""]}> - ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} - import { CheckoutProvider } from '@clerk/nextjs/experimental' - import { ClerkLoaded } from '@clerk/nextjs' - import { CheckoutFlow } from './CheckoutFlow' - - export function SubscriptionPage() { - // `` sets the context for the checkout flow. - // Any child component can now call `useCheckout()` to access this context. - return ( - -
-

Upgrade Your Plan

-

You are about to subscribe to our monthly plan

- - - -
-
- ) - } - ``` + + ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} + import { CheckoutProvider } from '@clerk/nextjs/experimental' + import { ClerkLoaded } from '@clerk/nextjs' + import { CheckoutFlow } from './CheckoutFlow' + + export function SubscriptionPage() { + // `` sets the context for the checkout flow. + // Any child component can now call `useCheckout()` to access this context. + return ( + +
+

Upgrade Your Plan

+

You are about to subscribe to our monthly plan

+ + + +
+
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} + import { CheckoutProvider } from '@clerk/clerk-react/experimental' + import { ClerkLoaded } from '@clerk/clerk-react' + import { CheckoutFlow } from './CheckoutFlow' + + export function SubscriptionPage() { + // `` sets the context for the checkout flow. + // Any child component can now call `useCheckout()` to access this context. + return ( + +
+

Upgrade Your Plan

+

You are about to subscribe to our monthly plan

+ + + +
+
+ ) + } + ``` +
- ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} - 'use client' + + ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} + 'use client' - import { useCheckout } from '@clerk/nextjs/experimental' + import { useCheckout } from '@clerk/nextjs/experimental' - export function CheckoutFlow() { - const { checkout } = useCheckout() - const { status } = checkout + export function CheckoutFlow() { + const { checkout } = useCheckout() + const { status } = checkout - if (status === 'needs_initialization') { - return - } + if (status === 'needs_initialization') { + return + } - return ( -
- - -
- ) - } + return ( +
+ + +
+ ) + } - function CheckoutInitialization() { - const { checkout } = useCheckout() - const { start, fetchStatus } = checkout + function CheckoutInitialization() { + const { checkout } = useCheckout() + const { start, fetchStatus } = checkout - return ( - - ) - } + return ( + + ) + } - function PaymentSection() { - const { checkout } = useCheckout() - - const { isConfirming, confirm, finalize, error } = checkout - - const [isProcessing, setIsProcessing] = useState(false) - const [paymentMethodId, setPaymentMethodId] = useState(null) - - const submitSelectedMethod = async () => { - if (isProcessing || !paymentMethodId) return - setIsProcessing(true) - - try { - // Confirm checkout with payment method - await confirm({ - paymentSourceId: paymentMethodId, - }) - // Calling `.finalize` enables you to sync the client-side state with the server-side state of your users. - // It revalidates all authorization checks computed within server components. - finalize({ redirectUrl: '/dashboard' }) - } catch (error) { - console.error('Payment failed:', error) - } finally { - setIsProcessing(false) + function PaymentSection() { + const { checkout } = useCheckout() + + const { isConfirming, confirm, finalize, error } = checkout + + const [isProcessing, setIsProcessing] = useState(false) + const [paymentMethodId, setPaymentMethodId] = useState(null) + + const submitSelectedMethod = async () => { + if (isProcessing || !paymentMethodId) return + setIsProcessing(true) + + try { + // Confirm checkout with payment method + await confirm({ + paymentSourceId: paymentMethodId, + }) + // Calling `.finalize` enables you to sync the client-side state with the server-side state of your users. + // It revalidates all authorization checks computed within server components. + finalize({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } finally { + setIsProcessing(false) + } } + + return ( + <> + {/* A component that lists a user's payment methods and allows them to select one. See an example: https://clerk.com/docs/reference/hooks/use-payment-methods#examples */} + + + {error &&
{error.message}
} + + + + ) } - return ( - <> - {/* A component that lists a user's payment methods and allows them to select one. See an example: https://clerk.com/docs/reference/hooks/use-payment-methods#examples */} - + function CheckoutSummary() { + const { checkout } = useCheckout() + const { plan, totals } = checkout + + return ( +
+

Order Summary

+ {plan?.name} + + {totals?.totalDueNow.currencySymbol} + {totals?.totalDueNow.amountFormatted} + +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} + import { useCheckout } from '@clerk/clerk-react/experimental' + + export function CheckoutFlow() { + const { checkout } = useCheckout() + const { status } = checkout + + if (status === 'needs_initialization') { + return + } + + return ( +
+ + +
+ ) + } - {error &&
{error.message}
} + function CheckoutInitialization() { + const { checkout } = useCheckout() + const { start, fetchStatus } = checkout - - - ) - } + ) + } - function CheckoutSummary() { - const { checkout } = useCheckout() - const { plan, totals } = checkout - - return ( -
-

Order Summary

- {plan?.name} - - {totals?.totalDueNow.currencySymbol} - {totals?.totalDueNow.amountFormatted} - -
- ) - } - ``` + function PaymentSection() { + const { checkout } = useCheckout() + + const { isConfirming, confirm, finalize, error } = checkout + + const [isProcessing, setIsProcessing] = useState(false) + const [paymentMethodId, setPaymentMethodId] = useState(null) + + const submitSelectedMethod = async () => { + if (isProcessing || !paymentMethodId) return + setIsProcessing(true) + + try { + // Confirm checkout with payment method + await confirm({ + paymentSourceId: paymentMethodId, + }) + // Calling `.finalize` enables you to sync the client-side state with the server-side state of your users. + // It revalidates all authorization checks computed within server components. + finalize({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } finally { + setIsProcessing(false) + } + } + + return ( + <> + {/* A component that lists a user's payment methods and allows them to select one. See an example: https://clerk.com/docs/reference/hooks/use-payment-methods#examples */} + + + {error &&
{error.message}
} + + + + ) + } + + function CheckoutSummary() { + const { checkout } = useCheckout() + const { plan, totals } = checkout + + return ( +
+

Order Summary

+ {plan?.name} + + {totals?.totalDueNow.currencySymbol} + {totals?.totalDueNow.amountFormatted} + +
+ ) + } + ``` +
@@ -320,48 +438,93 @@ The `useCheckout()` hook can be used with a context provider for managing state The following example shows an `` component that manages its own checkout flow. - ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} - 'use client' + + ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} + 'use client' - import { useCheckout } from '@clerk/nextjs/experimental' + import { useCheckout } from '@clerk/nextjs/experimental' - export function UpgradeButton({ - planId, - planPeriod, - }: { - planId: string - planPeriod: 'month' | 'annual' - }) { - // Pass options directly to the hook when not using a provider. - const { checkout } = useCheckout({ + export function UpgradeButton({ planId, planPeriod, - for: 'user', - }) - - const { start, status, isStarting, error } = checkout - - const handleStartCheckout = async () => { - try { - await start() - // In a real app, you would now use the `externalClientSecret` - // from the checkout object to render a payment form. - console.log('Checkout started! Status:', checkout.status) - } catch (e) { - console.error('Error starting checkout:', e) + }: { + planId: string + planPeriod: 'month' | 'annual' + }) { + // Pass options directly to the hook when not using a provider. + const { checkout } = useCheckout({ + planId, + planPeriod, + for: 'user', + }) + + const { start, status, isStarting, error } = checkout + + const handleStartCheckout = async () => { + try { + await start() + // In a real app, you would now use the `externalClientSecret` + // from the checkout object to render a payment form. + console.log('Checkout started! Status:', checkout.status) + } catch (e) { + console.error('Error starting checkout:', e) + } } + + return ( +
+ + {error &&

Error: {error.errors[0].message}

} +
+ ) } + ``` +
+ + + ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} + import { useCheckout } from '@clerk/clerk-react/experimental' - return ( -
- - {error &&

Error: {error.errors[0].message}

} -
- ) - } - ``` + export function UpgradeButton({ + planId, + planPeriod, + }: { + planId: string + planPeriod: 'month' | 'annual' + }) { + // Pass options directly to the hook when not using a provider. + const { checkout } = useCheckout({ + planId, + planPeriod, + for: 'user', + }) + + const { start, status, isStarting, error } = checkout + + const handleStartCheckout = async () => { + try { + await start() + // In a real app, you would now use the `externalClientSecret` + // from the checkout object to render a payment form. + console.log('Checkout started! Status:', checkout.status) + } catch (e) { + console.error('Error starting checkout:', e) + } + } + + return ( +
+ + {error &&

Error: {error.errors[0].message}

} +
+ ) + } + ``` +
diff --git a/docs/reference/hooks/use-payment-attempts.mdx b/docs/reference/hooks/use-payment-attempts.mdx index 968eb44acc..d9396f8b6e 100644 --- a/docs/reference/hooks/use-payment-attempts.mdx +++ b/docs/reference/hooks/use-payment-attempts.mdx @@ -162,137 +162,276 @@ The `usePaymentAttempts()` hook provides access to the payment attempts associat The following example demonstrates how to fetch and display a user's payment attempts. -```tsx -import { usePaymentAttempts } from '@clerk/nextjs/experimental' - -function PaymentAttemptsList() { - const { data, isLoading } = usePaymentAttempts({ - for: 'user', - pageSize: 10, - }) + + ```tsx + import { usePaymentAttempts } from '@clerk/nextjs/experimental' + + function PaymentAttemptsList() { + const { data, isLoading } = usePaymentAttempts({ + for: 'user', + pageSize: 10, + }) + + if (isLoading) { + return
Loading payment attempts...
+ } - if (isLoading) { - return
Loading payment attempts...
- } + if (!data || data.length === 0) { + return
No payment attempts found.
+ } - if (!data || data.length === 0) { - return
No payment attempts found.
+ return ( +
    + {data?.map((attempt) => ( +
  • + Payment #{attempt.id} - {attempt.status} +
    + Amount: {attempt.amount.amountFormatted} on {new Date(attempt.updatedAt).toLocaleString()} +
  • + ))} +
+ ) } + ``` +
- return ( -
    - {data?.map((attempt) => ( -
  • - Payment #{attempt.id} - {attempt.status} -
    - Amount: {attempt.amount.amountFormatted} on {new Date(attempt.updatedAt).toLocaleString()} -
  • - ))} -
- ) -} -``` - -### Infinite pagination - -The following example demonstrates how to implement infinite scrolling with payment attempts. - -```tsx -import { usePaymentAttempts } from '@clerk/nextjs/experimental' + + ```tsx + import { usePaymentAttempts } from '@clerk/clerk-react/experimental' -function InfinitePaymentAttempts() { - const { data, isLoading, hasNextPage, fetchNext } = usePaymentAttempts({ - for: 'user', - infinite: true, - pageSize: 20, - }) + function PaymentAttemptsList() { + const { data, isLoading } = usePaymentAttempts({ + for: 'user', + pageSize: 10, + }) - if (isLoading) { - return
Loading...
- } + if (isLoading) { + return
Loading payment attempts...
+ } - if (!data || data.length === 0) { - return
No payment attempts found.
- } + if (!data || data.length === 0) { + return
No payment attempts found.
+ } - return ( -
+ return (
    {data?.map((attempt) => (
  • - Payment attempt for {attempt.amount.amountFormatted} -
    - Status: {attempt.status} + Payment #{attempt.id} - {attempt.status}
    - {attempt.status === 'failed' && attempt.failedAt && ( - Failed At: {new Date(attempt.failedAt).toLocaleString()} - )} + Amount: {attempt.amount.amountFormatted} on {new Date(attempt.updatedAt).toLocaleString()}
  • ))}
+ ) + } + ``` + - {hasNextPage && } -
- ) -} -``` +### Infinite pagination -### Payment attempts history table +The following example demonstrates how to implement infinite scrolling with payment attempts. -The following example demonstrates how to use `usePaymentAttempts()` to display a detailed payment history table. + + ```tsx + import { usePaymentAttempts } from '@clerk/nextjs/experimental' -```tsx -import { usePaymentAttempts } from '@clerk/nextjs/experimental' + function InfinitePaymentAttempts() { + const { data, isLoading, hasNextPage, fetchNext } = usePaymentAttempts({ + for: 'user', + infinite: true, + pageSize: 20, + }) -function PaymentAttemptsHistory() { - const { data, isLoading } = usePaymentAttempts({ for: 'user' }) + if (isLoading) { + return
Loading...
+ } - if (isLoading) { - return
Loading payment attempts...
+ if (!data || data.length === 0) { + return
No payment attempts found.
+ } + + return ( +
+
    + {data?.map((attempt) => ( +
  • + Payment attempt for {attempt.amount.amountFormatted} +
    + Status: {attempt.status} +
    + {attempt.status === 'failed' && attempt.failedAt && ( + Failed At: {new Date(attempt.failedAt).toLocaleString()} + )} +
  • + ))} +
+ + {hasNextPage && } +
+ ) } + ``` +
+ + + ```tsx + import { usePaymentAttempts } from '@clerk/clerk-react/experimental' + + function InfinitePaymentAttempts() { + const { data, isLoading, hasNextPage, fetchNext } = usePaymentAttempts({ + for: 'user', + infinite: true, + pageSize: 20, + }) + + if (isLoading) { + return
Loading...
+ } + + if (!data || data.length === 0) { + return
No payment attempts found.
+ } - if (!data || data.length === 0) { - return
No payment attempts found.
+ return ( +
+
    + {data?.map((attempt) => ( +
  • + Payment attempt for {attempt.amount.amountFormatted} +
    + Status: {attempt.status} +
    + {attempt.status === 'failed' && attempt.failedAt && ( + Failed At: {new Date(attempt.failedAt).toLocaleString()} + )} +
  • + ))} +
+ + {hasNextPage && } +
+ ) } + ``` +
+ +### Payment attempts history table + +The following example demonstrates how to use `usePaymentAttempts()` to display a detailed payment history table. + + + ```tsx + import { usePaymentAttempts } from '@clerk/nextjs/experimental' + + function PaymentAttemptsHistory() { + const { data, isLoading } = usePaymentAttempts({ for: 'user' }) + + if (isLoading) { + return
Loading payment attempts...
+ } + + if (!data || data.length === 0) { + return
No payment attempts found.
+ } - const getStatusColor = (status: string) => { - switch (status) { - case 'paid': - return 'green' - case 'failed': - return 'red' - case 'pending': - return 'orange' - default: - return 'gray' + const getStatusColor = (status: string) => { + switch (status) { + case 'paid': + return 'green' + case 'failed': + return 'red' + case 'pending': + return 'orange' + default: + return 'gray' + } } + + return ( + + + + + + + + + + + + {data?.map((attempt) => ( + + + + + + + + ))} + +
Payment IDAmountStatusDatePayment Method
{attempt.id}{attempt.amount.amountFormatted}{attempt.status}{attempt.paidAt ? new Date(attempt.paidAt).toLocaleDateString() : '-'} + {attempt.paymentSource.cardType} ****{attempt.paymentSource.last4} +
+ ) } + ``` +
- return ( - - - - - - - - - - - - {data?.map((attempt) => ( - - - - - - + + ```tsx + import { usePaymentAttempts } from '@clerk/clerk-react/experimental' + + function PaymentAttemptsHistory() { + const { data, isLoading } = usePaymentAttempts({ for: 'user' }) + + if (isLoading) { + return
Loading payment attempts...
+ } + + if (!data || data.length === 0) { + return
No payment attempts found.
+ } + + const getStatusColor = (status: string) => { + switch (status) { + case 'paid': + return 'green' + case 'failed': + return 'red' + case 'pending': + return 'orange' + default: + return 'gray' + } + } + + return ( +
Payment IDAmountStatusDatePayment Method
{attempt.id}{attempt.amount.amountFormatted}{attempt.status}{attempt.paidAt ? new Date(attempt.paidAt).toLocaleDateString() : '-'} - {attempt.paymentSource.cardType} ****{attempt.paymentSource.last4} -
+ + + + + + + - ))} - -
Payment IDAmountStatusDatePayment Method
- ) -} -``` + + + {data?.map((attempt) => ( + + {attempt.id} + {attempt.amount.amountFormatted} + {attempt.status} + {attempt.paidAt ? new Date(attempt.paidAt).toLocaleDateString() : '-'} + + {attempt.paymentSource.cardType} ****{attempt.paymentSource.last4} + + + ))} + + + ) + } + ``` +
diff --git a/docs/reference/hooks/use-payment-methods.mdx b/docs/reference/hooks/use-payment-methods.mdx index f93745bcdf..65acb72c1e 100644 --- a/docs/reference/hooks/use-payment-methods.mdx +++ b/docs/reference/hooks/use-payment-methods.mdx @@ -120,122 +120,243 @@ The `usePaymentMethods()` hook provides access to the payment methods associated The following example demonstrates how to fetch and display a user's payment methods. -```tsx -import { usePaymentMethods } from '@clerk/nextjs/experimental' + + ```tsx + import { usePaymentMethods } from '@clerk/nextjs/experimental' + + function PaymentMethodsList() { + const { data, isLoading } = usePaymentMethods({ + for: 'user', + pageSize: 10, + }) + + if (isLoading) { + return
Loading payment methods...
+ } -function PaymentMethodsList() { - const { data, isLoading } = usePaymentMethods({ - for: 'user', - pageSize: 10, - }) + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/add-new-payment-method + return
No payment methods found. Please add a payment method to your account.
+ } - if (isLoading) { - return
Loading payment methods...
+ return ( +
    + {data?.map((method) => ( +
  • + {method.cardType} **** {method.last4} + {method.isDefault ? ' (Default)' : null} +
  • + ))} +
+ ) } + ``` +
- if (!data || data.length === 0) { - // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/add-new-payment-method - return
No payment methods found. Please add a payment method to your account.
- } + + ```tsx + import { usePaymentMethods } from '@clerk/clerk-react/experimental' + + function PaymentMethodsList() { + const { data, isLoading } = usePaymentMethods({ + for: 'user', + pageSize: 10, + }) - return ( -
    - {data?.map((method) => ( -
  • - {method.cardType} **** {method.last4} - {method.isDefault ? ' (Default)' : null} -
  • - ))} -
- ) -} -``` + if (isLoading) { + return
Loading payment methods...
+ } + + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/add-new-payment-method + return
No payment methods found. Please add a payment method to your account.
+ } + + return ( +
    + {data?.map((method) => ( +
  • + {method.cardType} **** {method.last4} + {method.isDefault ? ' (Default)' : null} +
  • + ))} +
+ ) + } + ``` +
### Infinite pagination The following example demonstrates how to implement infinite scrolling with payment methods. -```tsx -import { usePaymentMethods } from '@clerk/nextjs/experimental' + + ```tsx + import { usePaymentMethods } from '@clerk/nextjs/experimental' -function InfinitePaymentMethods() { - const { data, isLoading, hasNextPage, fetchNext } = usePaymentMethods({ - for: 'user', - infinite: true, - pageSize: 20, - }) + function InfinitePaymentMethods() { + const { data, isLoading, hasNextPage, fetchNext } = usePaymentMethods({ + for: 'user', + infinite: true, + pageSize: 20, + }) - if (isLoading) { - return
Loading...
- } + if (isLoading) { + return
Loading...
+ } + + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/add-new-payment-method + return
No payment methods found. Please add a payment method to your account.
+ } - if (!data || data.length === 0) { - // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/add-new-payment-method - return
No payment methods found. Please add a payment method to your account.
+ return ( +
+
    + {data?.map((method) => ( +
  • + {method.cardType} ending in {method.last4} + {method.status === 'expired' ? ' (Expired)' : null} + {method.status === 'disconnected' ? ' (Disconnected)' : null} +
  • + ))} +
+ + {hasNextPage && } +
+ ) } + ``` +
+ + + ```tsx + import { usePaymentMethods } from '@clerk/clerk-react/experimental' + + function InfinitePaymentMethods() { + const { data, isLoading, hasNextPage, fetchNext } = usePaymentMethods({ + for: 'user', + infinite: true, + pageSize: 20, + }) + + if (isLoading) { + return
Loading...
+ } - return ( -
-
    - {data?.map((method) => ( -
  • - {method.cardType} ending in {method.last4} - {method.status === 'expired' ? ' (Expired)' : null} - {method.status === 'disconnected' ? ' (Disconnected)' : null} -
  • - ))} -
+ if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/add-new-payment-method + return
No payment methods found. Please add a payment method to your account.
+ } - {hasNextPage && } -
- ) -} -``` + return ( +
+
    + {data?.map((method) => ( +
  • + {method.cardType} ending in {method.last4} + {method.status === 'expired' ? ' (Expired)' : null} + {method.status === 'disconnected' ? ' (Disconnected)' : null} +
  • + ))} +
+ + {hasNextPage && } +
+ ) + } + ``` +
### With checkout flow The following example demonstrates how to use `usePaymentMethods()` in a checkout flow to select an existing payment method. For more information on how to build a checkout flow with an existing payment method, see [Build a custom checkout flow](/docs/guides/development/custom-flows/billing/checkout-new-payment-method). -```tsx -import { usePaymentMethods, useCheckout } from '@clerk/nextjs/experimental' - -function CheckoutPaymentSelection() { - const { data, isLoading } = usePaymentMethods({ for: 'user' }) - const { checkout } = useCheckout() - const { confirm, finalize } = checkout - - const handlePaymentSubmit = async (paymentMethodId: string) => { - try { - // Confirm checkout with selected payment method - await confirm({ paymentSourceId: paymentMethodId }) - // Complete checkout and redirect - finalize({ redirectUrl: '/dashboard' }) - } catch (error) { - console.error('Payment failed:', error) + + ```tsx + import { usePaymentMethods, useCheckout } from '@clerk/nextjs/experimental' + + function CheckoutPaymentSelection() { + const { data, isLoading } = usePaymentMethods({ for: 'user' }) + const { checkout } = useCheckout() + const { confirm, finalize } = checkout + + const handlePaymentSubmit = async (paymentMethodId: string) => { + try { + // Confirm checkout with selected payment method + await confirm({ paymentSourceId: paymentMethodId }) + // Complete checkout and redirect + finalize({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } } - } - if (isLoading) { - return
Loading payment methods...
- } + if (isLoading) { + return
Loading payment methods...
+ } - if (!data || data.length === 0) { - // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/checkout-new-payment-method - return
No payment methods found. Please add a payment method to your account.
+ if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/checkout-new-payment-method + return
No payment methods found. Please add a payment method to your account.
+ } + + return ( +
+

Select a payment method

+ {data?.map((method) => ( + + ))} +
+ ) } + ``` +
+ + + ```tsx + import { usePaymentMethods, useCheckout } from '@clerk/clerk-react/experimental' + + function CheckoutPaymentSelection() { + const { data, isLoading } = usePaymentMethods({ for: 'user' }) + const { checkout } = useCheckout() + const { confirm, finalize } = checkout + + const handlePaymentSubmit = async (paymentMethodId: string) => { + try { + // Confirm checkout with selected payment method + await confirm({ paymentSourceId: paymentMethodId }) + // Complete checkout and redirect + finalize({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } + } + + if (isLoading) { + return
Loading payment methods...
+ } + + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/guides/development/custom-flows/billing/checkout-new-payment-method + return
No payment methods found. Please add a payment method to your account.
+ } - return ( -
-

Select a payment method

- {data?.map((method) => ( - - ))} -
- ) -} -``` + return ( +
+

Select a payment method

+ {data?.map((method) => ( + + ))} +
+ ) + } + ``` +
## Related guides diff --git a/docs/reference/hooks/use-plans.mdx b/docs/reference/hooks/use-plans.mdx index 80b2ae763e..07bc894fb2 100644 --- a/docs/reference/hooks/use-plans.mdx +++ b/docs/reference/hooks/use-plans.mdx @@ -120,71 +120,67 @@ The `usePlans()` hook provides access to the subscription plans available in you The following example shows how to fetch and display available plans. -```tsx -'use client' -import { usePlans } from '@clerk/nextjs/experimental' - -function PlansList() { - const { data, isLoading, hasNextPage, fetchNext, hasPreviousPage, fetchPrevious } = usePlans({ - for: 'user', - pageSize: 10, - }) - - if (isLoading) { - return
Loading plans...
- } - - return ( -
    - {data?.map((plan) => ( -
  • -

    {plan.name}

    -

    {plan.description}

    -

    Is free plan: {!plan.hasBaseFee ? 'Yes' : 'No'}

    -

    - Price per month: {plan.currency} {plan.amountFormatted} -

    -

    - Price per year: {plan.currency} {plan.annualAmountFormatted} equivalent to{' '} - {plan.currency} {plan.annualMonthlyAmountFormatted} per month -

    -

    Features:

    -
      - {plan.features.map((feature) => ( -
    • {feature.name}
    • - ))} -
    -
  • - ))} - - {hasNextPage && } - {hasPreviousPage && } -
- ) -} -``` - -### Infinite pagination + + ```tsx + 'use client' + import { usePlans } from '@clerk/nextjs/experimental' + + function PlansList() { + const { data, isLoading, hasNextPage, fetchNext, hasPreviousPage, fetchPrevious } = usePlans({ + for: 'user', + pageSize: 10, + }) + + if (isLoading) { + return
Loading plans...
+ } + + return ( +
    + {data?.map((plan) => ( +
  • +

    {plan.name}

    +

    {plan.description}

    +

    Is free plan: {!plan.hasBaseFee ? 'Yes' : 'No'}

    +

    + Price per month: {plan.currency} {plan.amountFormatted} +

    +

    + Price per year: {plan.currency} {plan.annualAmountFormatted} equivalent to{' '} + {plan.currency} {plan.annualMonthlyAmountFormatted} per month +

    +

    Features:

    +
      + {plan.features.map((feature) => ( +
    • {feature.name}
    • + ))} +
    +
  • + ))} -The following example demonstrates how to implement infinite scrolling with plans. + {hasNextPage && } + {hasPreviousPage && } +
+ ) + } + ``` +
-```tsx -'use client' -import { usePlans } from '@clerk/nextjs/experimental' + + ```tsx + import { usePlans } from '@clerk/clerk-react/experimental' -function InfinitePlansList() { - const { data, isLoading, hasNextPage, fetchNext } = usePlans({ - for: 'user', - infinite: true, - pageSize: 2, - }) + function PlansList() { + const { data, isLoading, hasNextPage, fetchNext, hasPreviousPage, fetchPrevious } = usePlans({ + for: 'user', + pageSize: 10, + }) - if (isLoading) { - return
Loading plans...
- } + if (isLoading) { + return
Loading plans...
+ } - return ( -
+ return (
    {data?.map((plan) => (
  • @@ -206,10 +202,110 @@ function InfinitePlansList() {
))} + + {hasNextPage && } + {hasPreviousPage && } + ) + } + ``` + + +### Infinite pagination - {hasNextPage && } -
- ) -} -``` +The following example demonstrates how to implement infinite scrolling with plans. + + + ```tsx + 'use client' + import { usePlans } from '@clerk/nextjs/experimental' + + function InfinitePlansList() { + const { data, isLoading, hasNextPage, fetchNext } = usePlans({ + for: 'user', + infinite: true, + pageSize: 2, + }) + + if (isLoading) { + return
Loading plans...
+ } + + return ( +
+
    + {data?.map((plan) => ( +
  • +

    {plan.name}

    +

    {plan.description}

    +

    Is free plan: {!plan.hasBaseFee ? 'Yes' : 'No'}

    +

    + Price per month: {plan.currency} {plan.amountFormatted} +

    +

    + Price per year: {plan.currency} {plan.annualAmountFormatted} equivalent to{' '} + {plan.currency} {plan.annualMonthlyAmountFormatted} per month +

    +

    Features:

    +
      + {plan.features.map((feature) => ( +
    • {feature.name}
    • + ))} +
    +
  • + ))} +
+ + {hasNextPage && } +
+ ) + } + ``` +
+ + + ```tsx + import { usePlans } from '@clerk/clerk-react/experimental' + + function InfinitePlansList() { + const { data, isLoading, hasNextPage, fetchNext } = usePlans({ + for: 'user', + infinite: true, + pageSize: 2, + }) + + if (isLoading) { + return
Loading plans...
+ } + + return ( +
+
    + {data?.map((plan) => ( +
  • +

    {plan.name}

    +

    {plan.description}

    +

    Is free plan: {!plan.hasBaseFee ? 'Yes' : 'No'}

    +

    + Price per month: {plan.currency} {plan.amountFormatted} +

    +

    + Price per year: {plan.currency} {plan.annualAmountFormatted} equivalent to{' '} + {plan.currency} {plan.annualMonthlyAmountFormatted} per month +

    +

    Features:

    +
      + {plan.features.map((feature) => ( +
    • {feature.name}
    • + ))} +
    +
  • + ))} +
+ + {hasNextPage && } +
+ ) + } + ``` +
diff --git a/docs/reference/hooks/use-statements.mdx b/docs/reference/hooks/use-statements.mdx index 679f736a4c..c4062232c2 100644 --- a/docs/reference/hooks/use-statements.mdx +++ b/docs/reference/hooks/use-statements.mdx @@ -162,75 +162,152 @@ The `useStatements()` hook provides access to the statements associated with a u The following example demonstrates how to fetch and display a user's statements. -```tsx -import { useStatements } from '@clerk/nextjs/experimental' + + ```tsx + import { useStatements } from '@clerk/nextjs/experimental' -function StatementsList() { - const { data, isLoading } = useStatements({ - for: 'user', - pageSize: 10, - }) + function StatementsList() { + const { data, isLoading } = useStatements({ + for: 'user', + pageSize: 10, + }) - if (isLoading) { - return
Loading statements...
- } - - if (!data || data.length === 0) { - return
No statements found.
- } + if (isLoading) { + return
Loading statements...
+ } - return ( -
    - {data?.map((statement) => ( -
  • - Statement ID: {statement.id} - {statement.status} -
    - Date: {statement.timestamp.toLocaleDateString()} -
  • - ))} -
- ) -} -``` + if (!data || data.length === 0) { + return
No statements found.
+ } -### Infinite pagination - -The following example demonstrates how to implement infinite scrolling with statements. + return ( +
    + {data?.map((statement) => ( +
  • + Statement ID: {statement.id} - {statement.status} +
    + Date: {statement.timestamp.toLocaleDateString()} +
  • + ))} +
+ ) + } + ``` +
-```tsx -import { useStatements } from '@clerk/nextjs/experimental' + + ```tsx + import { useStatements } from '@clerk/clerk-react/experimental' -function InfiniteStatements() { - const { data, isLoading, hasNextPage, fetchNext } = useStatements({ - for: 'user', - infinite: true, - pageSize: 20, - }) + function StatementsList() { + const { data, isLoading } = useStatements({ + for: 'user', + pageSize: 10, + }) - if (isLoading) { - return
Loading...
- } + if (isLoading) { + return
Loading statements...
+ } - if (!data || data.length === 0) { - return
No statements found.
- } + if (!data || data.length === 0) { + return
No statements found.
+ } - return ( -
+ return (
    {data?.map((statement) => (
  • - Statement ID: {statement.id} -
    - Amount: {statement.totals.grandTotal.amountFormatted} + Statement ID: {statement.id} - {statement.status}
    - Status: {statement.status} + Date: {statement.timestamp.toLocaleDateString()}
  • ))}
+ ) + } + ``` + - {hasNextPage && } -
- ) -} -``` +### Infinite pagination + +The following example demonstrates how to implement infinite scrolling with statements. + + + ```tsx + import { useStatements } from '@clerk/nextjs/experimental' + + function InfiniteStatements() { + const { data, isLoading, hasNextPage, fetchNext } = useStatements({ + for: 'user', + infinite: true, + pageSize: 20, + }) + + if (isLoading) { + return
Loading...
+ } + + if (!data || data.length === 0) { + return
No statements found.
+ } + + return ( +
+
    + {data?.map((statement) => ( +
  • + Statement ID: {statement.id} +
    + Amount: {statement.totals.grandTotal.amountFormatted} +
    + Status: {statement.status} +
  • + ))} +
+ + {hasNextPage && } +
+ ) + } + ``` +
+ + + ```tsx + import { useStatements } from '@clerk/clerk-react/experimental' + + function InfiniteStatements() { + const { data, isLoading, hasNextPage, fetchNext } = useStatements({ + for: 'user', + infinite: true, + pageSize: 20, + }) + + if (isLoading) { + return
Loading...
+ } + + if (!data || data.length === 0) { + return
No statements found.
+ } + + return ( +
+
    + {data?.map((statement) => ( +
  • + Statement ID: {statement.id} +
    + Amount: {statement.totals.grandTotal.amountFormatted} +
    + Status: {statement.status} +
  • + ))} +
+ + {hasNextPage && } +
+ ) + } + ``` +
diff --git a/docs/reference/hooks/use-subscription.mdx b/docs/reference/hooks/use-subscription.mdx index fef72ab651..9aed0e5c73 100644 --- a/docs/reference/hooks/use-subscription.mdx +++ b/docs/reference/hooks/use-subscription.mdx @@ -74,144 +74,366 @@ The `useSubscription()` hook provides access to subscription information for use The following example shows how to fetch and display subscription information. -```tsx -'use client' -import { useSubscription } from '@clerk/nextjs/experimental' + + ```tsx + 'use client' + import { useSubscription } from '@clerk/nextjs/experimental' -function SubscriptionInfo() { - const { data, isLoading, error } = useSubscription() + function SubscriptionInfo() { + const { data, isLoading, error } = useSubscription() - if (isLoading) { - return
Loading subscription...
- } + if (isLoading) { + return
Loading subscription...
+ } - if (error) { - return
Error loading subscription: {error.message}
- } + if (error) { + return
Error loading subscription: {error.message}
+ } + + if (!data) { + return
No subscription found
+ } - if (!data) { - return
No subscription found
+ return ( +
+

Your Subscription

+ {/* Display subscription details */} +
+ ) } + ``` +
- return ( -
-

Your Subscription

- {/* Display subscription details */} -
- ) -} -``` + + ```tsx + import { useSubscription } from '@clerk/clerk-react/experimental' + + function SubscriptionInfo() { + const { data, isLoading, error } = useSubscription() + + if (isLoading) { + return
Loading subscription...
+ } + + if (error) { + return
Error loading subscription: {error.message}
+ } + + if (!data) { + return
No subscription found
+ } + + return ( +
+

Your Subscription

+ {/* Display subscription details */} +
+ ) + } + ``` +
### Organization subscription The following example shows how to fetch an organization's subscription. -```tsx -'use client' -import { useSubscription } from '@clerk/nextjs/experimental' + + ```tsx + 'use client' + import { useSubscription } from '@clerk/nextjs/experimental' -function OrganizationSubscription() { - const { data, isLoading, revalidate } = useSubscription({ - for: 'organization', - keepPreviousData: true, - }) + function OrganizationSubscription() { + const { data, isLoading, revalidate } = useSubscription({ + for: 'organization', + keepPreviousData: true, + }) - const handleSubscriptionUpdate = async () => { - // After making changes to the subscription - await revalidate() - } + const handleSubscriptionUpdate = async () => { + // After making changes to the subscription + await revalidate() + } - if (isLoading) { - return
Loading organization subscription...
+ if (isLoading) { + return
Loading organization subscription...
+ } + + return ( +
+

Organization Subscription

+ {/* Display organization subscription details */} + +
+ ) } + ``` +
+ + + ```tsx + import { useSubscription } from '@clerk/clerk-react/experimental' - return ( -
-

Organization Subscription

- {/* Display organization subscription details */} - -
- ) -} -``` + function OrganizationSubscription() { + const { data, isLoading, revalidate } = useSubscription({ + for: 'organization', + keepPreviousData: true, + }) + + const handleSubscriptionUpdate = async () => { + // After making changes to the subscription + await revalidate() + } + + if (isLoading) { + return
Loading organization subscription...
+ } + + return ( +
+

Organization Subscription

+ {/* Display organization subscription details */} + +
+ ) + } + ``` +
### With error handling The following example shows how to handle subscription data with proper error states. -```tsx {{ filename: 'app/pricing/subscription-details/page.tsx' }} -'use client' -import { useSubscription } from '@clerk/nextjs/experimental' + + ```tsx {{ filename: 'app/pricing/subscription-details/page.tsx' }} + 'use client' + import { useSubscription } from '@clerk/nextjs/experimental' -function SubscriptionDetails() { - const { data: subscription, isLoading } = useSubscription() + function SubscriptionDetails() { + const { data: subscription, isLoading } = useSubscription() - if (isLoading) { - return
Loading subscription...
- } + if (isLoading) { + return
Loading subscription...
+ } + + if (!subscription) { + return
No subscription
+ } - if (!subscription) { - return
No subscription
+ return ( +
+

Subscription Details

+
+ Status: {subscription.status} +
+ +
+

Active since: {subscription.activeAt.toLocaleDateString()}

+ {subscription.pastDueAt && ( +

Past due since: {subscription.pastDueAt.toLocaleDateString()}

+ )} +
+ + {subscription.nextPayment && ( +
+

Next Payment

+

Amount: {subscription.nextPayment.amount.amountFormatted}

+

Due: {subscription.nextPayment.date.toLocaleDateString()}

+
+ )} + +
+

Subscription Items

+
    + {subscription.subscriptionItems.map((item) => ( +
  • {/* Display subscription item details */}
  • + ))} +
+
+
+ ) } - return ( -
-

Subscription Details

-
- Status: {subscription.status} + export default function Page() { + const { data, isLoading, error, isFetching, revalidate } = useSubscription() + + if (error) { + return ( +
+

Failed to load subscription

+

{error.message}

+ +
+ ) + } + + return ( +
+ {isLoading ? ( +
Loading...
+ ) : ( + <> +
{isFetching && Refreshing...}
+ {data ? :
No active subscription
} + + )}
+ ) + } + ``` + + + + ```tsx {{ filename: 'app/pricing/subscription-details/page.tsx' }} + 'use client' + import { useSubscription } from '@clerk/nextjs/experimental' -
-

Active since: {subscription.activeAt.toLocaleDateString()}

- {subscription.pastDueAt && ( -

Past due since: {subscription.pastDueAt.toLocaleDateString()}

+ function SubscriptionDetails() { + const { data: subscription, isLoading } = useSubscription() + + if (isLoading) { + return
Loading subscription...
+ } + + if (!subscription) { + return
No subscription
+ } + + return ( +
+

Subscription Details

+
+ Status: {subscription.status} +
+ +
+

Active since: {subscription.activeAt.toLocaleDateString()}

+ {subscription.pastDueAt && ( +

Past due since: {subscription.pastDueAt.toLocaleDateString()}

+ )} +
+ + {subscription.nextPayment && ( +
+

Next Payment

+

Amount: {subscription.nextPayment.amount.amountFormatted}

+

Due: {subscription.nextPayment.date.toLocaleDateString()}

+
)} + +
+

Subscription Items

+
    + {subscription.subscriptionItems.map((item) => ( +
  • {/* Display subscription item details */}
  • + ))} +
+
+ ) + } + + export default function Page() { + const { data, isLoading, error, isFetching, revalidate } = useSubscription() - {subscription.nextPayment && ( -
-

Next Payment

-

Amount: {subscription.nextPayment.amount.amountFormatted}

-

Due: {subscription.nextPayment.date.toLocaleDateString()}

+ if (error) { + return ( +
+

Failed to load subscription

+

{error.message}

+
- )} - -
-

Subscription Items

-
    - {subscription.subscriptionItems.map((item) => ( -
  • {/* Display subscription item details */}
  • - ))} -
+ ) + } + + return ( +
+ {isLoading ? ( +
Loading...
+ ) : ( + <> +
{isFetching && Refreshing...}
+ {data ? :
No active subscription
} + + )}
-
- ) -} + ) + } + ``` + + + + ```tsx {{ filename: 'src/pricing/subscription-details/page.tsx' }} + import { useSubscription } from '@clerk/clerk-react/experimental' + + function SubscriptionDetails() { + const { data: subscription, isLoading } = useSubscription() + + if (isLoading) { + return
Loading subscription...
+ } -export default function Page() { - const { data, isLoading, error, isFetching, revalidate } = useSubscription() + if (!subscription) { + return
No subscription
+ } - if (error) { return ( -
-

Failed to load subscription

-

{error.message}

- +
+

Subscription Details

+
+ Status: {subscription.status} +
+ +
+

Active since: {subscription.activeAt.toLocaleDateString()}

+ {subscription.pastDueAt && ( +

Past due since: {subscription.pastDueAt.toLocaleDateString()}

+ )} +
+ + {subscription.nextPayment && ( +
+

Next Payment

+

Amount: {subscription.nextPayment.amount.amountFormatted}

+

Due: {subscription.nextPayment.date.toLocaleDateString()}

+
+ )} + +
+

Subscription Items

+
    + {subscription.subscriptionItems.map((item) => ( +
  • {/* Display subscription item details */}
  • + ))} +
+
) } - return ( -
- {isLoading ? ( -
Loading...
- ) : ( - <> -
{isFetching && Refreshing...}
- {data ? :
No active subscription
} - - )} -
- ) -} -``` + export default function Page() { + const { data, isLoading, error, isFetching, revalidate } = useSubscription() + + if (error) { + return ( +
+

Failed to load subscription

+

{error.message}

+ +
+ ) + } + + return ( +
+ {isLoading ? ( +
Loading...
+ ) : ( + <> +
{isFetching && Refreshing...}
+ {data ? :
No active subscription
} + + )} +
+ ) + } + ``` + From 409c4e8cc6ff5449ea77042c3ad0e2d4e94ccadb Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Wed, 8 Oct 2025 15:19:00 -0600 Subject: [PATCH 14/14] Fix linting --- .../billing/add-new-payment-method.mdx | 280 +++++++++--------- 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/docs/_partials/billing/add-new-payment-method.mdx b/docs/_partials/billing/add-new-payment-method.mdx index 0286b0d868..ca4d52d839 100644 --- a/docs/_partials/billing/add-new-payment-method.mdx +++ b/docs/_partials/billing/add-new-payment-method.mdx @@ -4,160 +4,160 @@ The following example demonstrates how to create a billing page where a user can - **``**: Renders the payment form and handles the submission logic. It uses `usePaymentElement()` to get the `submit` function and `useUser()` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. -", ""]}> - ```tsx {{ filename: 'app/user/billing/page.tsx' }} - import { ClerkLoaded } from '@clerk/nextjs' - import { PaymentElementProvider } from '@clerk/nextjs/experimental' - import { AddPaymentMethodForm } from './AddPaymentMethodForm' - - export default function Page() { - return ( -
-

Billing Settings

- - - - - - -
- ) - } - ``` - - ```tsx {{ filename: 'app/user/billing/AddPaymentMethodForm.tsx' }} - 'use client' - import { useUser } from '@clerk/nextjs' - import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental' - import { useState } from 'react' - - export function AddPaymentMethodForm() { - const { user } = useUser() - const { submit, isFormReady } = usePaymentElement() - const [isSubmitting, setIsSubmitting] = useState(false) - const [error, setError] = useState(null) - - const handleAddPaymentMethod = async (e: React.FormEvent) => { - e.preventDefault() - if (!isFormReady || !user) { - return - } + ", ""]}> + ```tsx {{ filename: 'app/user/billing/page.tsx' }} + import { ClerkLoaded } from '@clerk/nextjs' + import { PaymentElementProvider } from '@clerk/nextjs/experimental' + import { AddPaymentMethodForm } from './AddPaymentMethodForm' + + export default function Page() { + return ( +
+

Billing Settings

+ + + + + + +
+ ) + } + ``` + + ```tsx {{ filename: 'app/user/billing/AddPaymentMethodForm.tsx' }} + 'use client' + import { useUser } from '@clerk/nextjs' + import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental' + import { useState } from 'react' + + export function AddPaymentMethodForm() { + const { user } = useUser() + const { submit, isFormReady } = usePaymentElement() + const [isSubmitting, setIsSubmitting] = useState(false) + const [error, setError] = useState(null) + + const handleAddPaymentMethod = async (e: React.FormEvent) => { + e.preventDefault() + if (!isFormReady || !user) { + return + } - setError(null) - setIsSubmitting(true) + setError(null) + setIsSubmitting(true) - try { - // 1. Submit the form to the payment provider to get a payment token - const { data, error } = await submit() + try { + // 1. Submit the form to the payment provider to get a payment token + const { data, error } = await submit() - // Usually a validation error from stripe that you can ignore. - if (error) { - setIsSubmitting(false) - return - } + // Usually a validation error from stripe that you can ignore. + if (error) { + setIsSubmitting(false) + return + } - // 2. Use the token to add the payment source to the user - await user.addPaymentSource(data) + // 2. Use the token to add the payment source to the user + await user.addPaymentSource(data) - // 3. Handle success (e.g., show a confirmation, clear the form) - alert('Payment method added successfully!') - } catch (err: any) { - setError(err.message || 'An unexpected error occurred.') - } finally { - setIsSubmitting(false) + // 3. Handle success (e.g., show a confirmation, clear the form) + alert('Payment method added successfully!') + } catch (err: any) { + setError(err.message || 'An unexpected error occurred.') + } finally { + setIsSubmitting(false) + } } - } - return ( -
-

Add a new payment method

- - - {error &&

{error}

} - - ) - } - ``` -
+ return ( +
+

Add a new payment method

+ + + {error &&

{error}

} + + ) + } + ``` +
-", ""]}> - ```tsx {{ filename: 'src/user/billing/page.tsx' }} - import { ClerkLoaded } from '@clerk/clerk-react' - import { PaymentElementProvider } from '@clerk/clerk-react/experimental' - import { AddPaymentMethodForm } from './AddPaymentMethodForm' - - export default function Page() { - return ( -
-

Billing Settings

- - - - - - -
- ) - } - ``` - - ```tsx {{ filename: 'src/user/billing/AddPaymentMethodForm.tsx' }} - import { useUser } from '@clerk/clerk-react' - import { usePaymentElement, PaymentElement } from '@clerk/clerk-react/experimental' - import { useState } from 'react' - - export function AddPaymentMethodForm() { - const { user } = useUser() - const { submit, isFormReady } = usePaymentElement() - const [isSubmitting, setIsSubmitting] = useState(false) - const [error, setError] = useState(null) - - const handleAddPaymentMethod = async (e: React.FormEvent) => { - e.preventDefault() - if (!isFormReady || !user) { - return - } + ", ""]}> + ```tsx {{ filename: 'src/user/billing/page.tsx' }} + import { ClerkLoaded } from '@clerk/clerk-react' + import { PaymentElementProvider } from '@clerk/clerk-react/experimental' + import { AddPaymentMethodForm } from './AddPaymentMethodForm' + + export default function Page() { + return ( +
+

Billing Settings

+ + + + + + +
+ ) + } + ``` + + ```tsx {{ filename: 'src/user/billing/AddPaymentMethodForm.tsx' }} + import { useUser } from '@clerk/clerk-react' + import { usePaymentElement, PaymentElement } from '@clerk/clerk-react/experimental' + import { useState } from 'react' + + export function AddPaymentMethodForm() { + const { user } = useUser() + const { submit, isFormReady } = usePaymentElement() + const [isSubmitting, setIsSubmitting] = useState(false) + const [error, setError] = useState(null) + + const handleAddPaymentMethod = async (e: React.FormEvent) => { + e.preventDefault() + if (!isFormReady || !user) { + return + } - setError(null) - setIsSubmitting(true) + setError(null) + setIsSubmitting(true) - try { - // 1. Submit the form to the payment provider to get a payment token - const { data, error } = await submit() + try { + // 1. Submit the form to the payment provider to get a payment token + const { data, error } = await submit() - // Usually a validation error from stripe that you can ignore. - if (error) { - setIsSubmitting(false) - return - } + // Usually a validation error from stripe that you can ignore. + if (error) { + setIsSubmitting(false) + return + } - // 2. Use the token to add the payment source to the user - await user.addPaymentSource(data) + // 2. Use the token to add the payment source to the user + await user.addPaymentSource(data) - // 3. Handle success (e.g., show a confirmation, clear the form) - alert('Payment method added successfully!') - } catch (err: any) { - setError(err.message || 'An unexpected error occurred.') - } finally { - setIsSubmitting(false) + // 3. Handle success (e.g., show a confirmation, clear the form) + alert('Payment method added successfully!') + } catch (err: any) { + setError(err.message || 'An unexpected error occurred.') + } finally { + setIsSubmitting(false) + } } - } - return ( -
-

Add a new payment method

- - - {error &&

{error}

} - - ) - } - ``` -
-
\ No newline at end of file + return ( +
+

Add a new payment method

+ + + {error &&

{error}

} + + ) + } + ``` + +