Skip to content

Human verification ​

A verify-you-are-human widget with the whole flow: idle, verifying, verified, and an error path.

Open in demo
Open in demo

Usage ​

v-model is the pass or fail boolean. verified carries the token a provider would hand back.

The widget makes no network request. The check is a timer, so the whole flow runs with no backend and nothing fails in the console.

Wiring it to a real provider such as Cloudflare Turnstile changes one function inside the component, runChallenge: load the provider's script once, render the widget into the element, and settle with the token from its callback. Nothing in the form around it changes, because v-model and verified already carry what a provider gives you.

The site key belongs in an environment variable rather than in SmartAdminConfig. The config holds the on-and-off switch, not a per-deployment value.

Feature flag ​

features.humanVerification is the one flag that ships off, so the demo's sign-in is two clicks. It is read at the call site, on the sign-in and sign-up pages, which keeps this a plain reusable widget. See Global config.

Examples ​

In a form ​

The usual shape: the submit button stays disabled until the widget passes.

Resetting and failing ​

reset() and fail() are exposed on the component instance. Call reset() after a failed submit so the reader can verify again, and fail() when your server refuses the token.

Clearing the bound value from the parent also sends a verified widget back to idle, so it can never read "Success!" while the form believes otherwise.

Disabled ​

API ​

Source: src/shared/components/common/SaHumanVerification.vue

Props ​

PropTypeDefaultDescription
modelValuebooleanfalsetrue once the challenge has passed.
durationnumber1400How long the simulated challenge takes, in milliseconds.
autobooleanfalseStarts the challenge on mount instead of waiting for a click.
disabledbooleanfalseDims the control and blocks it.
labelstring—The idle text and the control's accessible name. Defaults to "Verify you are human".
verifyingLabelstring—Defaults to "Verifying…".
verifiedLabelstring—Defaults to "Success!".
errorLabelstring—Defaults to "Verification failed. Click to retry."
brandstring'Smart Admin'The vendor mark in the corner. Decorative.

Emits ​

EventPayloadDescription
update:modelValuevalue: booleantrue on success, false on reset() and fail().
verifiedtoken: stringThe token. In the shipped widget it is a stand-in string.
error—Fires from fail().

Exposed ​

MemberTypeDescription
reset()() => voidBack to idle, and emits update:modelValue with false.
fail()() => voidInto the error state, and emits error.
state'idle' | 'verifying' | 'verified' | 'error'The current state. Also on the root as data-state.

Slots ​

None.

Accessibility ​

  • The control is a real role="checkbox" with aria-checked, named by label.
  • A visually hidden role="status" with aria-live="polite" announces every transition. The spinner is given an empty label on purpose, so the two do not announce "Verifying…" twice.
  • A passed challenge locks the control: re-running it is not something the reader should be able to do.
  • The error state is carried by an icon and by text, not by color alone.
  • The root is positioned, because the visually hidden status line is absolute and would otherwise anchor to the page and add to its height.