Authentication
Verify code
A centered card for the six-digit sign-in code sent by email.
<div class="grid min-h-dvh place-items-center bg-base-200 p-6">
<div class="flex w-full max-w-sm flex-col gap-6">
<a class="flex items-center gap-2 self-center font-medium" href="#">
<span class="grid size-8 place-items-center rounded-lg bg-primary text-primary-content">
<span class="icon icon-stack-2 size-5"></span>
</span>
Pelatform
</a>
<form class="card" id="verify-form" novalidate>
<div class="card-header">
<h1 class="card-title text-xl">Check your email</h1>
<p class="card-description">Enter the six-digit code sent to john@example.com.</p>
</div>
<div class="card-body">
<div class="field">
<label class="field-label" for="verify-code-input">Sign-in code</label>
<div class="input-otp w-full" style="--plf-input-otp-slot-size: 3rem" data-plf-input-otp data-plf-groups="3 3" id="verify-code">
<input class="input input-otp-input" type="text" id="verify-code-input" name="code" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" autocomplete="one-time-code" required aria-describedby="verify-code-help" aria-errormessage="verify-code-error">
</div>
<p class="field-help" id="verify-code-help">You can paste the whole code.</p>
<p class="field-error" id="verify-code-error" hidden></p>
</div>
</div>
<div class="card-actions flex-col">
<button class="btn btn-primary w-full">
<span class="btn-label">Verify</span>
<span class="btn-loading">
<span class="btn-icon btn-icon-loading"></span>
Verifying…
</span>
</button>
<div class="flex w-full flex-wrap justify-between gap-x-4 text-sm">
<button class="link link-muted" type="button" id="verify-resend">Resend code</button>
<a class="link link-muted" href="#">Use a different email</a>
</div>
</div>
</form>
</div>
</div>
<script>
const form = document.getElementById('verify-form');
const otp = document.getElementById('verify-code');
const input = document.getElementById('verify-code-input');
form.addEventListener('submit', async event => {
event.preventDefault();
const code = PLF.InputOTP.getInstance(otp);
if (!code.getState().complete) {
PLF.Field.error(input, 'Error: enter all six digits of the code.');
code.focus();
return;
}
// Your request; the button shows its loading part until it settles.
const response = await PLF.Button.loading(event.submitter, fetch('/sign-in/code', { method: 'POST', body: new FormData(form) }));
if (!response.ok) PLF.Field.error(input, 'Error: that code is not right. Use the latest code from your email.');
// Otherwise the code is right: continue to the dashboard.
});
document.getElementById('verify-resend').addEventListener('click', async () => {
// Your request for a new code; once it is sent, the boxes and the message clear.
const response = await fetch('/sign-in/code/resend', { method: 'POST' });
if (!response.ok) return;
const code = PLF.InputOTP.getInstance(otp);
code.clear();
PLF.Field.error(input, '');
code.focus();
});
</script><div class="plf:grid plf:min-h-dvh plf:place-items-center plf:bg-base-200 plf:p-6">
<div class="plf:flex plf:w-full plf:max-w-sm plf:flex-col plf:gap-6">
<a class="plf:flex plf:items-center plf:gap-2 plf:self-center plf:font-medium" href="#">
<span class="plf:grid plf:size-8 plf:place-items-center plf:rounded-lg plf:bg-primary plf:text-primary-content">
<span class="plf:icon plf:icon-stack-2 plf:size-5"></span>
</span>
Pelatform
</a>
<form class="plf:card" id="verify-form" novalidate>
<div class="plf:card-header">
<h1 class="plf:card-title plf:text-xl">Check your email</h1>
<p class="plf:card-description">Enter the six-digit code sent to john@example.com.</p>
</div>
<div class="plf:card-body">
<div class="plf:field">
<label class="plf:field-label" for="verify-code-input">Sign-in code</label>
<div class="plf:input-otp plf:w-full" style="--plf-input-otp-slot-size: 3rem" data-plf-input-otp data-plf-groups="3 3" id="verify-code">
<input class="plf:input plf:input-otp-input" type="text" id="verify-code-input" name="code" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" autocomplete="one-time-code" required aria-describedby="verify-code-help" aria-errormessage="verify-code-error">
</div>
<p class="plf:field-help" id="verify-code-help">You can paste the whole code.</p>
<p class="plf:field-error" id="verify-code-error" hidden></p>
</div>
</div>
<div class="plf:card-actions plf:flex-col">
<button class="plf:btn plf:btn-primary plf:w-full">
<span class="plf:btn-label">Verify</span>
<span class="plf:btn-loading">
<span class="plf:btn-icon plf:btn-icon-loading"></span>
Verifying…
</span>
</button>
<div class="plf:flex plf:w-full plf:flex-wrap plf:justify-between plf:gap-x-4 plf:text-sm">
<button class="plf:link plf:link-muted" type="button" id="verify-resend">Resend code</button>
<a class="plf:link plf:link-muted" href="#">Use a different email</a>
</div>
</div>
</form>
</div>
</div>
<script>
const form = document.getElementById('verify-form');
const otp = document.getElementById('verify-code');
const input = document.getElementById('verify-code-input');
form.addEventListener('submit', async event => {
event.preventDefault();
const code = PLF.InputOTP.getInstance(otp);
if (!code.getState().complete) {
PLF.Field.error(input, 'Error: enter all six digits of the code.');
code.focus();
return;
}
// Your request; the button shows its loading part until it settles.
const response = await PLF.Button.loading(event.submitter, fetch('/sign-in/code', { method: 'POST', body: new FormData(form) }));
if (!response.ok) PLF.Field.error(input, 'Error: that code is not right. Use the latest code from your email.');
// Otherwise the code is right: continue to the dashboard.
});
document.getElementById('verify-resend').addEventListener('click', async () => {
// Your request for a new code; once it is sent, the boxes and the message clear.
const response = await fetch('/sign-in/code/resend', { method: 'POST' });
if (!response.ok) return;
const code = PLF.InputOTP.getInstance(otp);
code.clear();
PLF.Field.error(input, '');
code.focus();
});
</script>'use client';
import { useRef, useState, type CSSProperties, type FormEvent } from 'react';
import {
Button, CardActions, CardBody, CardDescription, CardHeader, Field, Icon, InputOTP, Link, linkClass,
} from '@pelatform/react';
export function Example() {
const input = useRef<HTMLInputElement>(null);
const [code, setCode] = useState('');
const [error, setError] = useState('');
const [verifying, setVerifying] = useState(false);
async function verify(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
if (code.length < 6) {
setError('Error: enter all six digits of the code.');
input.current?.focus();
return;
}
setVerifying(true);
try {
// Your request; the button shows its loading part until it settles.
const response = await fetch('/sign-in/code', { method: 'POST', body: new FormData(event.currentTarget) });
if (!response.ok) setError('Error: that code is not right. Use the latest code from your email.');
// Otherwise the code is right: continue to the dashboard.
} finally {
setVerifying(false);
}
}
async function resend() {
// Your request for a new code; once it is sent, the boxes and the message clear.
const response = await fetch('/sign-in/code/resend', { method: 'POST' });
if (!response.ok) return;
setCode('');
setError('');
input.current?.focus();
}
return (
<div className="grid min-h-dvh place-items-center bg-base-200 p-6">
<div className="flex w-full max-w-sm flex-col gap-6">
<a className="flex items-center gap-2 self-center font-medium" href="#">
<span className="grid size-8 place-items-center rounded-lg bg-primary text-primary-content">
<Icon name="stack-2" className="size-5" />
</span>
Pelatform
</a>
<form className="card" noValidate onSubmit={verify}>
<CardHeader>
<h1 className="card-title text-xl">Check your email</h1>
<CardDescription>Enter the six-digit code sent to john@example.com.</CardDescription>
</CardHeader>
<CardBody>
<Field
label="Sign-in code"
help="You can paste the whole code."
error={error}
style={{ '--plf-input-otp-slot-size': '3rem' } as CSSProperties}
>
<InputOTP
ref={input}
name="code"
maxLength={6}
groups={[3, 3]}
containerClassName="w-full"
required
value={code}
onValueChange={next => {
// The next edit clears the message.
setCode(next);
setError('');
}}
/>
</Field>
</CardBody>
<CardActions className="flex-col">
<Button color="primary" className="w-full" loading={verifying} loadingText="Verifying…">
Verify
</Button>
<div className="flex w-full flex-wrap justify-between gap-x-4 text-sm">
<button className={linkClass({ variant: 'muted' })} type="button" onClick={resend}>Resend code</button>
<Link variant="muted" href="#">Use a different email</Link>
</div>
</CardActions>
</form>
</div>
</div>
);
}'use client';
import { useRef, useState, type CSSProperties, type FormEvent } from 'react';
import {
Button, CardActions, CardBody, CardDescription, CardHeader, Field, Icon, InputOTP, Link, linkClass,
} from '@pelatform/react/prefixed';
export function Example() {
const input = useRef<HTMLInputElement>(null);
const [code, setCode] = useState('');
const [error, setError] = useState('');
const [verifying, setVerifying] = useState(false);
async function verify(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
if (code.length < 6) {
setError('Error: enter all six digits of the code.');
input.current?.focus();
return;
}
setVerifying(true);
try {
// Your request; the button shows its loading part until it settles.
const response = await fetch('/sign-in/code', { method: 'POST', body: new FormData(event.currentTarget) });
if (!response.ok) setError('Error: that code is not right. Use the latest code from your email.');
// Otherwise the code is right: continue to the dashboard.
} finally {
setVerifying(false);
}
}
async function resend() {
// Your request for a new code; once it is sent, the boxes and the message clear.
const response = await fetch('/sign-in/code/resend', { method: 'POST' });
if (!response.ok) return;
setCode('');
setError('');
input.current?.focus();
}
return (
<div className="plf:grid plf:min-h-dvh plf:place-items-center plf:bg-base-200 plf:p-6">
<div className="plf:flex plf:w-full plf:max-w-sm plf:flex-col plf:gap-6">
<a className="plf:flex plf:items-center plf:gap-2 plf:self-center plf:font-medium" href="#">
<span className="plf:grid plf:size-8 plf:place-items-center plf:rounded-lg plf:bg-primary plf:text-primary-content">
<Icon name="stack-2" className="plf:size-5" />
</span>
Pelatform
</a>
<form className="plf:card" noValidate onSubmit={verify}>
<CardHeader>
<h1 className="plf:card-title plf:text-xl">Check your email</h1>
<CardDescription>Enter the six-digit code sent to john@example.com.</CardDescription>
</CardHeader>
<CardBody>
<Field
label="Sign-in code"
help="You can paste the whole code."
error={error}
style={{ '--plf-input-otp-slot-size': '3rem' } as CSSProperties}
>
<InputOTP
ref={input}
name="code"
maxLength={6}
groups={[3, 3]}
containerClassName="plf:w-full"
required
value={code}
onValueChange={next => {
// The next edit clears the message.
setCode(next);
setError('');
}}
/>
</Field>
</CardBody>
<CardActions className="plf:flex-col">
<Button color="primary" className="plf:w-full" loading={verifying} loadingText="Verifying…">
Verify
</Button>
<div className="plf:flex plf:w-full plf:flex-wrap plf:justify-between plf:gap-x-4 plf:text-sm">
<button className={linkClass({ variant: 'muted' })} type="button" onClick={resend}>Resend code</button>
<Link variant="muted" href="#">Use a different email</Link>
</div>
</CardActions>
</form>
</div>
</div>
);
}<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/button.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/card.min.css">
<link rel="stylesheet" href="components/link.min.css">
<link rel="stylesheet" href="components/input-otp.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/input-otp.min.js" defer></script>
<script src="components/button.min.js" defer></script>
<script src="components/field.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/button.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/card.prefixed.min.css">
<link rel="stylesheet" href="components/link.prefixed.min.css">
<link rel="stylesheet" href="components/input-otp.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/input-otp.min.js" defer></script>
<script src="components/button.min.js" defer></script>
<script src="components/field.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>