ClickCaptcha
click-captchaCollects an ordered set of relative image coordinates with undo, refresh, and keyboard crosshair controls.
Usage
Basic usage
Given the background image and prompt image, maxPoints is triggered to trigger onComplete; the encoding and request are taken over by the consumer.
Points selected 0/3
Click on the three prompts in the picture
<ClickCaptcha
backgroundSrc={bgUrl}
hintSrc={hintUrl}
status={status}
onComplete={async (points) => {
setStatus("verifying");
const ok = await api.verify(encodePoints(points)); // The agreement is up to you
setStatus(ok ? "success" : "failed");
}}
onRefresh={() => reloadCaptcha()}
/>Controlled point
points + onPointsChange are held externally; the relative coordinates are 0~1, converted according to the benchmark required by the own backend.
Points selected 0/4
- Externally held point array, which can be cleared/played back by itself
const [points, setPoints] = useState<CaptchaPoint[]>([]);
<ClickCaptcha
backgroundSrc={bgUrl}
points={points}
onPointsChange={setPoints}
maxPoints={4}
/>Verifying/Failed/Passed
status driver three states: verifying locks interaction, failed jitters and clears points, success locks.
Verifying…
Verification failed, please try again
Verified
<ClickCaptcha backgroundSrc={bgUrl} status="verifying" />
<ClickCaptcha backgroundSrc={bgUrl} status="failed" />
<ClickCaptcha backgroundSrc={bgUrl} status="success" />Loading
During loading, cover the mask and disable clicking (used when the backend releases new images).
Points selected 0/3
<ClickCaptcha backgroundSrc={bgUrl} loading />When to use
Use ClickCaptcha when an admin login flow requires click-based bot verification. It handles only the interaction from a supplied background and hint image to an ordered list of relative click coordinates. The component owns coordinate conversion, numbered markers, undo and refresh interactions, keyboard access, and reduced-motion behavior.
Intentionally out of scope: network requests and backend protocols. Endpoint paths, captchaId session semantics, and captchaInfo encoding vary across providers such as BuildAdmin, Tencent Captcha, and GeeTest; embedding any one protocol would create library-level API debt. Encode the returned points for your backend and send the request in onComplete, then set status to success or failed from the result.
InputOTP is different: it captures a numeric SMS or email code and does not perform bot verification. Combine ClickCaptcha with LoginForm through the extra slot and beforeSubmit to implement submit → verify captcha → continue login.
Import
import { ClickCaptcha } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| backgroundSrc | string | — | Required background-image URL supplied by the application. |
| hintSrc | string | — | Hint-image URL, such as the image accompanying "Click in order: book, mountain, water"; rendered at the right of the prompt row. |
| hintText | ReactNode | locale.clickCaptcha.hint | Prompt content. |
| maxPoints | number | 3 | Number of points to collect before calling onComplete. |
| points | CaptchaPoint[] | — | Controlled points; omit to manage them internally. |
| defaultPoints | CaptchaPoint[] | [] | Initial points when uncontrolled. |
| loading | boolean | false | Covers the image and disables selection while the application loads a replacement image. |
| status | "idle" | "verifying" | "failed" | "success" | "idle" | Verification state. failed shakes and clears points; verifying and success lock interaction. |
| disabled | boolean | false | Disables all interaction, including refresh. |
| aspectRatio | number | 2 | Image area aspect ratio (310×155 is common in BuildAdmin click-select images) |
| keyboardStep | number | 0.02 | Distance moved by each keyboard crosshair step, in relative coordinates. |
| className | string | — | Additional class name for the root element. |
Events
| Event | Type | Description |
|---|---|---|
| onPointsChange | (points: CaptchaPoint[]) => void | Called after points are added, undone, or cleared; update controlled state here. |
| onComplete | (points: CaptchaPoint[]) => void | Called when maxPoints have been collected; encode the protocol payload and send the request here. |
| onRefresh | () => void | Called when the user requests another image. The component clears points; the application must update backgroundSrc. |
CaptchaPoint = { x: number; y: number }, where x and y are relative coordinates in [0,1] measured from the top-left of the displayed image.
Usage guidelines
- Keep backend protocols outside the component. Leave
captchaId,captchaInfoencoding, and endpoint paths in application code. ClickCaptcha only returns coordinates, so changing providers does not require changing the component. - Coordinates are relative values, not pixels. With scaling, responsive layouts, or high-DPI displays, multiply
xby the source-image width andyby its height before sending pixels to the backend. - Update controlled state. If
pointsis passed, callsetStatefromonPointsChange; otherwise clicks cannot add visible markers, as with any controlled component. - Set
status="failed"after a rejected verification. The component shakes and clears the points; clearing them again in application code causes a duplicate flash. - The shake uses
motion-safe:and is disabled byprefers-reduced-motion. Failure is still announced as text, so feedback does not depend on animation. - If an image fails to load, the component shows fallback copy instead of a blank frame and lets the user request another image.
- The image area is focusable. Arrow keys move the crosshair, Enter or Space places a point, and Backspace undoes the last point. Do not add
pointer-events-noneor override itstabIndex. - SliderCaptcha is not currently included. If added, it should follow the same protocol-independent UI boundary.
Related
LoginForm · InputOTP · Field · ImageCropper