Ejemplos de integración de frontend
El widget es un custom element estándar, así que funciona en cada framework sin un wrapper que instalar. La forma siempre es la misma: carga el paquete una vez (integración del lado del cliente), renderiza <caputchin-widget sitekey="cpt_pub_..."> dentro de tu formulario, y lee el campo oculto caputchin-token que inyecta cuando el visitante supera el reto. Para un juego, cámbialo por <caputchin-game ... game="caputchin/games/leaf-memory">.
Los ejemplos de abajo difieren solo en la sintaxis de cada framework y en su única peculiaridad de custom element.
HTML plano
El campo inyectado viaja junto a un POST de formulario normal, así que no hay nada que cablear:
<script src="https://cdn.jsdelivr.net/npm/@caputchin/widget@3/dist/widget.js"></script>
<form action="/contact" method="POST">
<input name="email" type="email" required />
<caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
<button type="submit">Send</button>
</form>React
Importa una vez al arranque, luego lee el campo de FormData al enviar:
import "@caputchin/widget";
export function ContactForm() {
async function handleSubmit(e) {
e.preventDefault();
const data = new FormData(e.currentTarget);
await fetch("/api/contact", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email: data.get("email"), token: data.get("caputchin-token") }),
});
}
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" required />
<caputchin-widget sitekey="cpt_pub_..." />
<button type="submit">Send</button>
</form>
);
}Si usas TypeScript con React, declara ambos elementos una vez para que JSX los acepte:
// caputchin.d.ts
import type { DetailedHTMLProps, HTMLAttributes } from "react";
declare module "react" {
namespace JSX {
interface IntrinsicElements {
"caputchin-widget": DetailedHTMLProps<HTMLAttributes<HTMLElement> & { sitekey: string }, HTMLElement>;
"caputchin-game": DetailedHTMLProps<HTMLAttributes<HTMLElement> & { sitekey: string; game?: string; games?: string }, HTMLElement>;
}
}
}Esta forma declare module "react" es específica del JSX de React. En TypeScript plano los elementos son solo HTMLElement y no necesitan declaración, y los demás frameworks de abajo tipan los custom elements a su manera, así que solo necesitas este bloque en un proyecto de React.
Vue
Dile al compilador de Vue que las etiquetas caputchin- son custom elements, para que no intente resolverlas como componentes:
// vite.config.js
export default {
plugins: [vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith("caputchin-") } } })],
};<script setup>
import "@caputchin/widget";
function onSubmit(e) {
const data = new FormData(e.target);
// send data.get("caputchin-token") to your backend
}
</script>
<template>
<form @submit.prevent="onSubmit">
<input name="email" type="email" required />
<caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
<button type="submit">Send</button>
</form>
</template>Svelte
Svelte renderiza los custom elements tal cual, sin configuración necesaria:
<script>
import "@caputchin/widget";
function onSubmit(e) {
const data = new FormData(e.currentTarget);
// send data.get("caputchin-token") to your backend
}
</script>
<form on:submit|preventDefault={onSubmit}>
<input name="email" type="email" required />
<caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
<button type="submit">Send</button>
</form>Angular
Añade CUSTOM_ELEMENTS_SCHEMA al módulo o al componente standalone para que Angular permita la etiqueta desconocida, e importa el paquete una vez (en main.ts):
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@caputchin/widget";
@Component({
selector: "contact-form",
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<form (submit)="onSubmit($event)">
<input name="email" type="email" required />
<caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
<button type="submit">Send</button>
</form>
`,
})
export class ContactFormComponent {
onSubmit(e: Event) {
const data = new FormData(e.target as HTMLFormElement);
// send data.get("caputchin-token") to your backend
}
}Next.js
El mismo código de React funciona. El custom element se renderiza como una etiqueta vacía durante el render en el servidor y se actualiza en el cliente una vez que el paquete carga, así que no hace falta ningún tratamiento especial más allá de importar @caputchin/widget en un componente de cliente (o cargar el script del CDN con next/script).
Véase también
- Integración del lado del cliente para las opciones de carga.
- Integración del lado del servidor para la mitad de backend.