Documentation · itzsa
Captcha
Company-standard canvas captcha with ref + onVerified, attempt limits, and structured API error props. Client friction only — pair with a server check for sensitive flows.
Live demo#
Same API as production — try charset mode, length, and a simulated bad API response.
Letters & numbers — match case exactly as shown
0/6 · 5 left
onVerified → false · validate() → false
Installation#
npm package or copy-paste from the itzsa registry.
pnpm add @itzsa/captcha$ pnpm dlx shadcn@latest add https://itzsa.acharya-suman.com.np/r/captcha.jsonGetting started#
Minimal usage is enough for most forms.
Minimal — ref + onVerified#
Yes: this pattern is fully supported. onVerified(true) when the answer is accepted; onVerified(false) on wrong input, refresh, or clear.
import { useRef, useState } from "react";
import { Captcha, type CaptchaHandle } from "@itzsa/captcha";
export function LoginGate() {
const captchaRef = useRef<CaptchaHandle>(null);
const [verified, setVerified] = useState(false);
function handleCaptchaVerified(valid: boolean) {
setVerified(valid);
}
function onSubmit() {
// Imperative check before submit
if (!captchaRef.current?.validate()) return;
// …submit form
}
return (
<>
<Captcha ref={captchaRef} onVerified={handleCaptchaVerified} />
<button type="button" disabled={!verified} onClick={onSubmit}>
Continue
</button>
</>
);
}Checklist
onVerifiedupdates UI (enable submit).captchaRef.current?.validate()before submit.- Optional:
captchaRef.current?.refresh()after a failed host API.
Server verify / API errors#
Pass verify for async checks. Throw or return false on bad API calls — onError receives a CaptchaError. Use error for host-driven messages.
const [apiError, setApiError] = useState<string | null>(null);
<Captcha
ref={captchaRef}
error={apiError}
maxAttempts={5}
verify={async ({ value, challengeId }) => {
const res = await fetch("/api/captcha/verify", {
method: "POST",
body: JSON.stringify({ value, challengeId }),
});
if (!res.ok) throw new Error("verify_failed"); // → onError + status "error"
return true;
}}
onError={(err) => console.warn(err.code, err.message)}
onVerified={handleCaptchaVerified}
/>Props#
Public surface of Captcha. Tables use a solid white background.
Core#
Core
| Prop | Type | Default | Description |
|---|---|---|---|
| length / chars | number | 6 | Number of characters in the challenge (3–16). |
| charsetMode | "both" | "letters" | "numbers" | "both" | Letters + digits, letters only, or digits only. |
| excludeAmbiguous | boolean | true | Drop look-alikes (0 / O / 1 / l / I). |
| caseSensitive | boolean | true | Exact case match (ignored when charsetMode is numbers). |
| theme | "light" | "dark" | "system" | "system" | Canvas color scheme. |
| noise | number | 0.55 | Interference intensity from 0 to 1. |
| maxAttempts | number | 5 | Failures before status becomes locked. |
| onVerified | (valid: boolean) => void | - | Called with true when the answer is accepted, false when cleared / wrong / refreshed. Works with only ref + onVerified. |
Verify & errors#
Verify & errors
| Prop | Type | Default | Description |
|---|---|---|---|
| verify | (payload) => boolean | Promise<boolean> | - | Optional server check. Return false or throw on a bad API call. |
| verifyTimeoutMs | number | 15000 | Abort verify() after this many milliseconds. |
| error | string | null | - | Controlled host/API error (e.g. login 429). Shown under the field. |
| loading | boolean | - | Controlled loading while a host API is in flight. |
| onError | (error: CaptchaError) => void | - | Structured failures: invalid, verify_failed, network, timeout, max_attempts, … |
| onLock | (error: CaptchaError) => void | - | Fired when maxAttempts is reached. |
| autoRefreshOnInvalid | boolean | false | Issue a new challenge after a wrong answer. |
| autoRefreshOnError | boolean | false | Issue a new challenge after a verify/API failure. |
Chrome & styling#
Chrome
| Prop | Type | Default | Description |
|---|---|---|---|
| label / showLabel / required | string / boolean / boolean | "Security check" / true / false | Accessible field label and required marker. |
| messages | CaptchaMessages | - | Override placeholders and status copy. |
| showRefresh / showCounter / showStatus | boolean | true | Toggle chrome pieces. |
| className / canvasClassName / inputClassName / … | string | - | Styling hooks for root, canvas, input, refresh, label, error. |
| value / defaultValue / disabled / id / name | — | - | Form control helpers. |
Imperative API#
CaptchaHandle via ref — same object as captchaRef.current.
CaptchaHandle
| Prop | Type | Default | Description |
|---|---|---|---|
| refresh() | () => void | - | New challenge, clear input, reset attempts. |
| reset() | () => void | - | Clear input without regenerating the challenge. |
| validate() | () => boolean | - | True if currently valid (or local match). |
| getValue() | () => string | - | Current user input. |
| getChallengeId() | () => string | - | Opaque id for this challenge (server correlation). |
| getStatus() / getAttempts() | () => CaptchaStatus / number | - | Latest status and failure count. |
| unlock() | (opts?) => void | - | Clear lock; refreshes by default. |
Registry#
Installs under components/itzsa/captcha (nested components/ui).
captcha.json
https://itzsa.acharya-suman.com.np/r/captcha.json