Appearance
Tracking login flow state ​
All of Privy's custom login hooks return a state
variable that tracks the user's current state in the login flow. You can use this to conditionally render your UI based on the user's current login state.
Conditional rendering ​
You can use the state.status
variable to conditionally render your UI based on the user's current state in the login flow. For example, you might track the state
variable from the useLoginWithEmail
hook to conditionally render a button that sends the OTP or a button that logs the user in with the OTP.
tsx
import {useState} from 'react';
import {useLoginWithEmail} from '@privy-io/react-auth';
export function LoginScreen() {
const [code, setCode] = useState('');
const [email, setEmail] = useState('');
const {state, sendCode, loginWithCode} = useLoginWithEmail();
return (
<div>
<div>
<input onChange={(e) => setEmail(e.target.value)} />
<button
// Keeps button disabled while code is being sent
disabled={state.status === 'sending-code'}
onClick={() => sendCode({email})}
>
Send Code
</button>
{state.status === 'sending-code' && (
// Shows only while the code is sending
<span>Sending Code...</span>
)}
</div>
<div>
<input onChange={(e) => setCode(e.target.value)} />
<button
// Keeps button disabled until the code has been sent
disabled={state.status !== 'awaiting-code-input'}
onClick={() => loginWithCode({code})}
>
Login
</button>
</div>
{state.status === 'submitting-code' && (
// Shows only while the login is being attempted
<span>Logging in...</span>
)}
</div>
);
}
Error state ​
When state.status
is equal to 'error'
, the error value is accessible as state.error
which can be used to render inline hints in a login form.
tsx
import {useLoginWithEmail, hasError} from '@privy-io/react-auth';
export function LoginScreen() {
const {state, sendCode, loginWithCode} = useLoginWithEmail();
return (
<div>
{/* other ui... */}
{state.status === 'error' && (
<>
<span className="text-red-600">There was an error</span>
<span className="text-red-400">{state.error.message}</span>
</>
)}
{hasError(state) && (
// The `hasError` util is also provided as a convenience
// (for typescript users, this provides the same type narrowing as above)
<>
<span className="text-red-600">There was an error</span>
<span className="text-red-400">{state.error.message}</span>
</>
)}
</div>
);
}