useSignUp()
and useSignIn()
If Clerk's prebuilt components don't meet your specific needs or if you require more control over the authentication flow, Clerk enables you to build fully custom sign-up and sign-in flows using the useSignUp()
and useSignIn()
React hooks.
useSignUp()
The useSignUp()
hook gives you access to the SignUp
object and its available methods in order to build a custom sign-up flow. The SignUp
object will also contain the state of the sign-up attempt that is currently in progress, which gives you the ability to examine all the details and act accordingly.
Usage
Getting access to the SignUp
object from inside one of your components is simple.
The following example accesses the SignUp
object to check the current sign-up attempt's status.
The useSignUp()
hook can only be used inside a <ClerkProvider>
context.
import { useSignUp } from '@clerk/nextjs'; export default function SignUpStep() { const { isLoaded, signUp } = useSignUp(); if (!isLoaded) { // Handle loading state return null; } return ( <div> The current sign up attempt status is {signUp.status}. </div> ); }
The more involved example below shows an approach for creating a custom form for registering users. In this case, the Password strategy is used. This example assumes that additional requirements, like username or phone, are not enabled.
import { useState } from "react"; import { useSignUp } from "@clerk/nextjs"; import { useRouter } from "next/router"; export default function SignUpForm() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [pendingVerification, setPendingVerification] = useState(false); const [code, setCode] = useState(""); const router = useRouter(); // start the sign up process. const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { await signUp.create({ emailAddress, password, }); // send the email. await signUp.prepareEmailAddressVerification({ strategy: "email_code" }); // change the UI to our pending section. setPendingVerification(true); } catch (err: any) { console.error(JSON.stringify(err, null, 2)); } }; // This verifies the user using email code that is delivered. const onPressVerify = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { const completeSignUp = await signUp.attemptEmailAddressVerification({ code, }); if (completeSignUp.status !== "complete") { /* investigate the response, to see if there was an error or if the user needs to complete more steps.*/ console.log(JSON.stringify(completeSignUp, null, 2)); } if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }) router.push("/"); } } catch (err: any) { console.error(JSON.stringify(err, null, 2)); } }; return ( <div> {!pendingVerification && ( <form> <div> <label htmlFor="email">Email</label> <input onChange={(e) => setEmailAddress(e.target.value)} id="email" name="email" type="email" /> </div> <div> <label htmlFor="password">Password</label> <input onChange={(e) => setPassword(e.target.value)} id="password" name="password" type="password" /> </div> <button onClick={handleSubmit}>Sign up</button> </form> )} {pendingVerification && ( <div> <form> <input value={code} placeholder="Code..." onChange={(e) => setCode(e.target.value)} /> <button onClick={onPressVerify}> Verify Email </button> </form> </div> )} </div> ); }
useSignIn()
The useSignIn()
hook gives you access to the SignIn
object and its available methods in order to build a custom sign-in flow. The SignIn
object will also contain the state of the sign-in attempt that is currently in progress, which gives you the ability to examine all the details and act accordingly.
Usage
Getting access to the SignIn
object from inside one of your components is simple.
The following example accesses the SignIn
object to check the current sign-in attempt's status.
The useSignIn()
hook can only be used inside a <ClerkProvider>
context.
import { useSignIn } from '@clerk/nextjs'; export default function SignInStep() { const { isLoaded, signIn } = useSignIn(); if (!isLoaded) { // Handle loading state return null; } return ( <div> The current sign in attempt status is {signIn.status}. </div> ); }
The more involved example below shows an approach for creating a custom form for signing in users. In this case, a Password strategy is used.
import { useState } from "react"; import { useSignIn } from "@clerk/nextjs"; import { useRouter } from "next/router"; export default function SignInForm() { const { isLoaded, signIn, setActive } = useSignIn(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const router = useRouter(); // start the sign In process. const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { const result = await signIn.create({ identifier: emailAddress, password, }); if (result.status === "complete") { console.log(result); await setActive({ session: result.createdSessionId }); router.push("/") } else { /*Investigate why the login hasn't completed */ console.log(result); } } catch (err: any) { console.error("error", err.errors[0].longMessage) } }; return ( <div> <form> <div> <label htmlFor="email">Email</label> <input onChange={(e) => setEmailAddress(e.target.value)} id="email" name="email" type="email" /> </div> <div> <label htmlFor="password">Password</label> <input onChange={(e) => setPassword(e.target.value)} id="password" name="password" type="password" /> </div> <button onClick={handleSubmit}>Sign In</button> </form> </div> ); }