> ## Documentation Index
> Fetch the complete documentation index at: https://formpaste.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Snippets por framework

> Un formulario simple y ya conectado para cada framework compatible, pégalo y funciona.

Cada snippet a continuación hace lo mismo: envía un POST a
`https://api.formpaste.com/submit` con el `access_key` de tu formulario, y
maneja la respuesta de éxito/error. Son intencionalmente simples: un campo
de correo, un campo de mensaje y manejo del envío, no una librería de
componentes con estilo. Cambia `YOUR_ACCESS_KEY` por la clave de acceso que
se muestra en la pestaña Setup de tu formulario.

<Tabs>
  <Tab title="HTML">
    Un formulario simple, sin necesidad de JavaScript.

    ```html theme={null}
    <form action="https://api.formpaste.com/submit" method="POST">
      <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY">
      <input type="email" name="email" placeholder="Your email" required>
      <textarea name="message" placeholder="Your message" required></textarea>
      <button type="submit">Send</button>
    </form>
    ```
  </Tab>

  <Tab title="React">
    <Tabs>
      <Tab title="TypeScript">
        ```tsx theme={null}
        import { useState } from "react";

        export function ContactForm() {
          const [status, setStatus] = useState<"idle" | "sending" | "ok" | "error">("idle");

          async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
            e.preventDefault();
            setStatus("sending");
            const form = new FormData(e.currentTarget);
            const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form as any) });
            setStatus(res.ok ? "ok" : "error");
          }

          if (status === "ok") return <p>Thanks - your message was sent.</p>;

          return (
            <form onSubmit={onSubmit}>
              <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
              <input type="email" name="email" placeholder="Your email" required />
              <textarea name="message" placeholder="Your message" required />
              <button type="submit" disabled={status === "sending"}>Send</button>
              {status === "error" && <p>Something went wrong. Please try again.</p>}
            </form>
          );
        }
        ```
      </Tab>

      <Tab title="JavaScript">
        ```jsx theme={null}
        import { useState } from "react";

        export function ContactForm() {
          const [status, setStatus] = useState("idle"); // "idle" | "sending" | "ok" | "error"

          async function onSubmit(e) {
            e.preventDefault();
            setStatus("sending");
            const form = new FormData(e.currentTarget);
            const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form) });
            setStatus(res.ok ? "ok" : "error");
          }

          if (status === "ok") return <p>Thanks - your message was sent.</p>;

          return (
            <form onSubmit={onSubmit}>
              <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
              <input type="email" name="email" placeholder="Your email" required />
              <textarea name="message" placeholder="Your message" required />
              <button type="submit" disabled={status === "sending"}>Send</button>
              {status === "error" && <p>Something went wrong. Please try again.</p>}
            </form>
          );
        }
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Next.js">
    Un componente de cliente, agrega `"use client"` ya que mantiene el estado del formulario.

    <Tabs>
      <Tab title="TypeScript">
        ```tsx theme={null}
        "use client";
        import { useState } from "react";

        export function ContactForm() {
          const [status, setStatus] = useState<"idle" | "sending" | "ok" | "error">("idle");

          async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
            e.preventDefault();
            setStatus("sending");
            const form = new FormData(e.currentTarget);
            const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form as any) });
            setStatus(res.ok ? "ok" : "error");
          }

          if (status === "ok") return <p>Thanks - your message was sent.</p>;

          return (
            <form onSubmit={onSubmit}>
              <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
              <input type="email" name="email" placeholder="Your email" required />
              <textarea name="message" placeholder="Your message" required />
              <button type="submit" disabled={status === "sending"}>Send</button>
              {status === "error" && <p>Something went wrong. Please try again.</p>}
            </form>
          );
        }
        ```
      </Tab>

      <Tab title="JavaScript">
        ```jsx theme={null}
        "use client";
        import { useState } from "react";

        export function ContactForm() {
          const [status, setStatus] = useState("idle"); // "idle" | "sending" | "ok" | "error"

          async function onSubmit(e) {
            e.preventDefault();
            setStatus("sending");
            const form = new FormData(e.currentTarget);
            const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form) });
            setStatus(res.ok ? "ok" : "error");
          }

          if (status === "ok") return <p>Thanks - your message was sent.</p>;

          return (
            <form onSubmit={onSubmit}>
              <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
              <input type="email" name="email" placeholder="Your email" required />
              <textarea name="message" placeholder="Your message" required />
              <button type="submit" disabled={status === "sending"}>Send</button>
              {status === "error" && <p>Something went wrong. Please try again.</p>}
            </form>
          );
        }
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Astro">
    Un formulario sin JS, funciona igual que la versión HTML simple.

    ```astro theme={null}
    ---
    // src/components/ContactForm.astro - a no-JS form that posts to Formpaste.
    ---
    <form action="https://api.formpaste.com/submit" method="POST">
      <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
      <input type="email" name="email" placeholder="Your email" required />
      <textarea name="message" placeholder="Your message" required></textarea>
      <button type="submit">Send</button>
    </form>
    ```
  </Tab>

  <Tab title="Vue">
    <Tabs>
      <Tab title="TypeScript">
        ```vue theme={null}
        <script setup lang="ts">
        import { ref } from "vue";

        const status = ref<"idle" | "sending" | "ok" | "error">("idle");

        async function onSubmit(e: Event) {
          status.value = "sending";
          const form = new FormData(e.target as HTMLFormElement);
          const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form as any) });
          status.value = res.ok ? "ok" : "error";
        }
        </script>

        <template>
          <p v-if="status === 'ok'">Thanks - your message was sent.</p>
          <form v-else @submit.prevent="onSubmit">
            <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
            <input type="email" name="email" placeholder="Your email" required />
            <textarea name="message" placeholder="Your message" required></textarea>
            <button type="submit" :disabled="status === 'sending'">Send</button>
            <p v-if="status === 'error'">Something went wrong. Please try again.</p>
          </form>
        </template>
        ```
      </Tab>

      <Tab title="JavaScript">
        ```vue theme={null}
        <script setup>
        import { ref } from "vue";

        const status = ref("idle"); // "idle" | "sending" | "ok" | "error"

        async function onSubmit(e) {
          status.value = "sending";
          const form = new FormData(e.target);
          const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form) });
          status.value = res.ok ? "ok" : "error";
        }
        </script>

        <template>
          <p v-if="status === 'ok'">Thanks - your message was sent.</p>
          <form v-else @submit.prevent="onSubmit">
            <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
            <input type="email" name="email" placeholder="Your email" required />
            <textarea name="message" placeholder="Your message" required></textarea>
            <button type="submit" :disabled="status === 'sending'">Send</button>
            <p v-if="status === 'error'">Something went wrong. Please try again.</p>
          </form>
        </template>
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Svelte">
    <Tabs>
      <Tab title="TypeScript">
        ```svelte theme={null}
        <script lang="ts">
          let status: "idle" | "sending" | "ok" | "error" = "idle";

          async function onSubmit(e: SubmitEvent) {
            status = "sending";
            const form = new FormData(e.target as HTMLFormElement);
            const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form as any) });
            status = res.ok ? "ok" : "error";
          }
        </script>

        {#if status === "ok"}
          <p>Thanks - your message was sent.</p>
        {:else}
          <form on:submit|preventDefault={onSubmit}>
            <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
            <input type="email" name="email" placeholder="Your email" required />
            <textarea name="message" placeholder="Your message" required></textarea>
            <button type="submit" disabled={status === "sending"}>Send</button>
            {#if status === "error"}<p>Something went wrong. Please try again.</p>{/if}
          </form>
        {/if}
        ```
      </Tab>

      <Tab title="JavaScript">
        ```svelte theme={null}
        <script>
          let status = "idle"; // "idle" | "sending" | "ok" | "error"

          async function onSubmit(e) {
            status = "sending";
            const form = new FormData(e.target);
            const res = await fetch("https://api.formpaste.com/submit", { method: "POST", body: new URLSearchParams(form) });
            status = res.ok ? "ok" : "error";
          }
        </script>

        {#if status === "ok"}
          <p>Thanks - your message was sent.</p>
        {:else}
          <form on:submit|preventDefault={onSubmit}>
            <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
            <input type="email" name="email" placeholder="Your email" required />
            <textarea name="message" placeholder="Your message" required></textarea>
            <button type="submit" disabled={status === "sending"}>Send</button>
            {#if status === "error"}<p>Something went wrong. Please try again.</p>{/if}
          </form>
        {/if}
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

> Descubre nuestras [plantillas de formulario de contacto](https://formpaste.com/templates/) personalizables y listas para copiar y pegar.

## Obtener el snippet con tu clave de acceso real ya incluida

En lugar de copiar y pegar `YOUR_ACCESS_KEY` a mano, puedes:

* Copiar el snippet desde la pestaña **Setup** del formulario en el [panel](https://app.formpaste.com), ya tiene tu clave de acceso incorporada.
* Pedirle a un agente conectado a través del [servidor MCP](/docs/agents/mcp-server) que llame a
  [`get_snippet`](/docs/agents/get-snippet) con tu `formId`, devuelve el
  mismo snippet con la clave de acceso real ya incluida en lugar de un marcador de posición.

## Nombres de campo reservados

`/submit` maneja algunos nombres de campo de forma especial, evita reutilizarlos
para tus propios datos:

| Campo        | Propósito                                                                                                             |
| ------------ | --------------------------------------------------------------------------------------------------------------------- |
| `access_key` | Obligatorio. Identifica a qué formulario pertenece el envío.                                                          |
| `botcheck`   | Honeypot. Déjalo vacío y oculto para los visitantes reales, consulta [Filtrado de spam](/docs/es/features/spam-filtering). |
| `_ts`        | Opcional. Una marca de tiempo usada para heurísticas de spam basadas en el tiempo.                                    |
| `redirect`   | Opcional. Una URL a la que redirigir tras un envío exitoso sin JS, consulta [Redirecciones](/docs/es/features/redirects).  |

Cualquier otro nombre de campo es tuyo: `email`, `message`, `name`, o
cualquier otro que necesite tu formulario.
