The form type
Checkbox mode
Section titled “Checkbox mode”The default. CapType renders Cap’s widget: a checkbox reading “Verify you’re human”. Cap starts solving in the
background as soon as the visitor moves the mouse or presses a key, so ticking it is usually instant.
$builder->add('cap', CapType::class);<cap-widget id="contact_cap" data-cap-hidden-field-name="contact[cap]" required data-controller="silarhi--cap-bundle--cap" data-silarhi-cap="checkbox" data-cap-api-endpoint="https://cap.example.com/site-key/" data-cap-lang="en"></cap-widget><script type="module" src="/bundles/silarhicap/cap.js"></script>The widget creates the hidden contact[cap] input itself and fills it once solved: the token is submitted with the
other fields. While the field is required (the default), the browser refuses to submit an unticked widget and shows
“Please verify you’re human”. With 'required' => false, or in a novalidate form, the bundle solves it on submit
instead.
Invisible mode
Section titled “Invisible mode”Nothing to see or click: the challenge is solved with Cap’s programmatic mode when the visitor focuses a field of the form, and on submit if they were faster.
$builder->add('cap', CapType::class, [ 'mode' => CapType::MODE_INVISIBLE,]);<input type="hidden" id="contact_cap" name="contact[cap]" data-silarhi-cap="invisible" data-cap-api-endpoint="https://cap.example.com/site-key/" .../>Submitting waits for the challenge: the form gets aria-busy="true" meanwhile, and the
cap:solving and cap:solved events let you show a spinner. Solving takes from a few
hundred milliseconds to a few seconds, depending on the difficulty of the site key and the device.
Invisible mode needs the JavaScript of the bundle, the checkbox mode only needs the widget.
Options
Section titled “Options”| Option | Default | Description |
|---|---|---|
mode |
'checkbox' |
CapType::MODE_CHECKBOX or CapType::MODE_INVISIBLE |
locale |
the request locale | Language of the widget labels (data-cap-lang): see labels and languages |
i18n |
[] |
Widget labels, keyed by the suffix of their data-cap-i18n-* attribute |
worker_count |
null |
Number of solver workers (data-cap-worker-count); Cap uses one per CPU core |
troubleshooting_url |
null |
The “Troubleshooting” link Cap shows a blocked visitor (data-cap-troubleshooting-url) |
csp_nonce |
null |
Nonce of the script and of the widget styles: see Content Security Policy |
constraints |
[new Cap()] |
Replace it to customize the messages: [new Cap(message: '…', missingMessage: '…')] |
attr |
[] |
Attributes of the <cap-widget> (or of the hidden input), e.g. a class |
required |
true |
Checkbox mode: the browser asks to tick the widget before submitting |
mapped is false and label is false by default: the widget carries its own label.
Errors
Section titled “Errors”Errors stay on the field (error_bubbling is false): form_row(form.cap) renders them under the widget.
| Code | Message | When |
|---|---|---|
Cap::MISSING_ERROR |
Please verify you are human. | No token submitted |
Cap::INVALID_ERROR |
The human verification failed, please try again. | Cap rejected the token, or could not be reached |
{{ error }} in a custom message is Cap’s reason ("Token expired", "Token not found"…) or the bundle’s
(connection-failed, bad-response, invalid-json).
A token is single-use. When the form comes back with an error (any field), the widget renders again and the visitor solves a new challenge.
Styling
Section titled “Styling”Cap’s widget is styled with CSS variables:
cap-widget { --cap-background: var(--bs-body-bg); --cap-border-color: var(--bs-border-color); --cap-color: var(--bs-body-color); --cap-widget-width: 100%;}The full list is in Cap’s documentation.
