---
title: "Ventana Modal Emergente en Carrd: Cómo Añadir Una a Tu Sitio (2026)"
description: "Añade una ventana modal emergente en Carrd con código gratis para copiar y pegar: captura de email con temporizador, activada por clic e intención de salida, con ejemplos modernos de dialog y popover."
date: 2026-01-21
categories: ["web-development"]
tags: ["carrd","popup","email-capture"]
---

import Button from "@components/widgets/Button.astro";
import { Picture } from "astro:assets";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";
import imag1 from "@assets/images/24/02/carrd-back-to-top-embed.png";

Las ventanas emergentes tienen mala reputación, sobre todo porque la gente abusa de ellas. Pero un modal bien sincronizado puede capturar emails, anunciar ofertas o destacar algo urgente sin saturar tu página principal. El momento y la moderación importan más que el código.

Añadir una ventana modal emergente a un sitio web de Carrd requiere un elemento Embed y algo de código para copiar y pegar. Carrd no tiene una función de ventanas emergentes integrada (nada relacionado con popups en el changelog visible hasta septiembre de 2026), así que esta guía de ventana modal emergente en Carrd te da tres versiones que funcionan (captura de email con temporizador, activada por clic e intención de salida) construidas sobre el elemento moderno `<dialog>` y la Popover API, en lugar de los trucos con div y z-index de hace unos años.

[Carrd](https://go.bitdoze.com/carrd) mantiene las cosas simples a propósito. Está bien. Un elemento Embed es todo lo que necesitas aquí.

<Button link="https://go.bitdoze.com/carrd" text="Crea con Carrd" />

Algunos tutoriales de Carrd:

- [Añadir scroll suave a Carrd](https://www.bitdoze.com/carrd-smooth-scroll/)
- [Añadir un slider de testimonios a Carrd](https://www.bitdoze.com/carrd-testimonial-slider/)
- [Añadir un alternador de modo oscuro a Carrd](https://www.bitdoze.com/es/alternador-modo-oscuro-carrd/)
- [Añadir un menú flotante a Carrd](https://www.bitdoze.com/carrd-floating-menu/)
- [Añadir un menú lateral a Carrd](https://www.bitdoze.com/carrd-sidebar-menu/)
- [Añadir una cabecera fija a Carrd](https://www.bitdoze.com/add-stickey-header-carrd/)

> La lista completa con plugins, temas y tutoriales de Carrd la puedes encontrar en mi sitio web **[carrdme.com](https://carrdme.com/)**.

## Por qué añadir ventanas emergentes a tu sitio Carrd

Las ventanas emergentes sirven para tareas concretas:

1. Captura de emails. Haz crecer tu lista de newsletter sin dedicar espacio destacado de la página a formularios de registro.
2. Anuncios. Informa a los visitantes sobre ofertas, nuevos productos o novedades que vale la pena conocer.
3. Lightboxes de imágenes. Muestra versiones más grandes de imágenes de portafolio o fotos de productos.
4. Intención de salida. Capta a los visitantes antes de que se vayan con una última oferta.
5. Mensajes de bienvenida. Saluda a los visitantes nuevos o señala algo urgente.

Úsalas con criterio. No las muestres en el instante en que alguien llega a tu página. Dale unos segundos para mirar alrededor primero.

El límite de frecuencia importa tanto como el momento. Todo el código de abajo usa `sessionStorage`, así que un visitante ve la ventana emergente una vez por sesión del navegador. Cambia a `localStorage` (con una marca de tiempo de expiración) si prefieres una vez por semana. Esa decisión vive en el código. No necesitas un plugin para ello.

## ¿Qué plan de Carrd necesitas?

<Notice type="warning" title="Necesitas Carrd Pro Standard (19 $/año) o superior">
Los embeds (el elemento que hace posible cualquier ventana modal emergente en Carrd) requieren <strong>Pro Standard (19 $/año, 10 sitios)</strong> o superior. Las cuentas Free y Pro Lite (9 $/año) no pueden añadir código personalizado en absoluto, así que si estás en esos planes, nada de este tutorial se renderizará. <strong>Pro Plus (49 $/año, 25 sitios)</strong> añade Advanced Settings: IDs y atributos personalizados, además de eventos <strong>On Click</strong> en los botones, que te dan botones activadores más limpios para la Opción 2.
</Notice>

Precios comprobados en la página Pro de Carrd en septiembre de 2026. Existen variantes por número de sitios si gestionas más: Standard cuesta 39 $/año para 25 sitios, 69 $/año para 50 y 119 $/año para 100. El plan de 19 $/año es suficiente para la mayoría de los que trabajan en solitario.

Este es el coste principal de todo el montaje. El código de la ventana emergente en sí es gratis; los 19 $/año son la entrada para los embeds de Carrd Pro Standard. Analizo cada plan de Carrd en mi [reseña de Carrd](https://www.bitdoze.com/carrd-review/).

Si solo necesitas un formulario de registro o una capa de confirmación y el precio te parece excesivo para código personalizado, salta a "¿De verdad necesitas código personalizado?" más abajo. Hay caminos que evitan el elemento Embed por completo.

<Button link="https://go.bitdoze.com/carrd" text="Ver planes de Carrd" variant="outline" />

## Cómo añadir una ventana modal emergente a Carrd

La configuración es la misma para las tres opciones. Un elemento Embed contiene tu HTML, CSS y un poco de JavaScript. Luego eliges el tipo de ventana emergente que encaja con tu objetivo.

### Paso 1: Añade un elemento Embed

En el editor de Carrd, pulsa el signo `+` y añade un elemento Embed en cualquier parte de la página (la colocación en el editor visual no importa; definiremos la ubicación real en los ajustes). Configúralo así:

- **Type:** Code
- **Style:** Hidden, **Body End**

<Picture formats={["webp"]} fallbackFormat="webp" src={imag1} alt="Ajustes del elemento embed de Carrd mostrando Type en Code y Style en Hidden, con el desplegable de ubicación al lado" />

La captura muestra el desplegable de ubicación en Head. Cámbialo a **Body End** para las Opciones 1 y 3. La Opción 2 es la excepción: su botón activador es visible en la página, así que ese embed usa **Style: Inline** (detalles en la Opción 2).

<Notice type="info" title="Type debe ser Code">
Establece Type en <strong>Code</strong>, no en Iframe. El marcado, los estilos y el script de la ventana emergente viven todos en este único embed. Carrd permite explícitamente las etiquetas <code>&lt;style&gt;</code> y <code>&lt;script&gt;</code> aquí.
</Notice>

Los embeds ocultos pueden ir en Head, Body Top o Body End. Head funciona, pero inyectar marcado `<div>` en `<head>` solo funciona porque el parser de HTML lo traslada forzosamente a `<body>`. Frágil y confuso cuando depuras. Body End te da un orden del DOM determinista: tu marcado queda antes del script que lo consulta, sin trucos del parser. Es la opción por defecto que recomiendo para cada ventana emergente con embed en Carrd.

![Diagrama del DOM de una página de Carrd con el embed de la ventana emergente colocado en Body End y el modal renderizándose en la capa superior del navegador sobre el contenido de la página](@assets/images/26/01/carrd-popup-embed-placement.svg)

Una vez que pegues el código (siguiente paso), publica y revisa la URL en vivo. Ahí es donde ocurre la verdadera prueba del código de ventana emergente en Carrd. Más sobre eso en la sección de verificación.

### Paso 2: Elige tu tipo de ventana emergente

Tres versiones, tres tareas. Elige una por página.

<ListCheck>
<ul>
<li>Hacer crecer una newsletter → Opción 1, ventana emergente de captura de email con temporizador (se muestra tras una espera)</li>
<li>Mostrar detalles, términos o una oferta bajo demanda → Opción 2, ventana emergente activada por clic</li>
<li>Oferta de última oportunidad en escritorio → Opción 3, ventana emergente de intención de salida (con alternativa de scroll para móvil)</li>
</ul>
</ListCheck>

<Notice type="warning" title="No mezcles opciones a ciegas">
Cada opción trae sus propios IDs de elemento (<code>emailModal</code>, <code>svcModal</code>, <code>exitModal</code>), así que dos opciones distintas pueden convivir en un sitio. Pegar la misma opción dos veces (para tener dos ventanas con temporizador, por ejemplo) romperá ambas. Si de verdad quieres una segunda copia, renombra primero cada ID, clase, variable y función del segundo bloque.
</Notice>

---

## Opción 1: Ventana emergente de captura de email con temporizador

Esta ventana emergente aparece tras una espera e incluye un formulario de registro de email. Es la opción por defecto adecuada para hacer crecer una newsletter. Es la clásica ventana emergente de email en Carrd.

La versión de abajo usa el elemento nativo `<dialog>` y `showModal()`. Eso te da mucho gratis: Escape la cierra, la página de detrás no se puede pulsar ni alcanzar con Tab mientras está abierta, y se renderiza en la capa superior del navegador, así que nada de peleas de z-index con el marcado de Carrd. Una cosa que `showModal()` no hace es impedir que la página de detrás haga scroll, así que el CSS incluye una regla `:has()` de una línea que bloquea el scroll mientras el diálogo está abierto. El soporte de navegadores es universal desde Firefox 98 y Safari 15.4 (marzo de 2022) según los datos de compatibilidad de MDN, comprobado en septiembre de 2026.

```html
<style>
  :root {
    --popup-bg: #ffffff;
    --popup-overlay: rgba(0, 0, 0, 0.6);
    --popup-accent: #4f46e5;
    --popup-text: #1f2937;
    --popup-secondary: #6b7280;
    --popup-radius: 16px;
    --popup-width: 450px;
    --popup-delay: 3000; /* ms before the popup shows; keep in sync with setTimeout() */
  }

  dialog#emailModal {
    border: 0;
    border-radius: var(--popup-radius);
    padding: 0;
    max-width: var(--popup-width);
    width: 90%;
    background: var(--popup-bg);
    color: var(--popup-text);
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  }

  dialog#emailModal::backdrop {
    background: var(--popup-overlay);
  }

  body:has(dialog#emailModal[open]) {
    overflow: hidden;
  }

  @media (prefers-reduced-motion: no-preference) {
    dialog#emailModal[open] {
      animation: modalIn 0.3s ease;
    }

    @keyframes modalIn {
      from {
        opacity: 0;
        transform: scale(0.8);
      }
      to {
        opacity: 1;
        transform: scale(1);
      }
    }
  }

  .modal-inner {
    padding: 40px;
    position: relative;
  }

  .modal-close {
    position: absolute;
    top: 15px;
    right: 15px;
    width: 32px;
    height: 32px;
    border: none;
    background: #f3f4f6;
    border-radius: 50%;
    cursor: pointer;
    font-size: 20px;
    color: var(--popup-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s;
  }

  .modal-close:hover {
    background: #e5e7eb;
  }

  .modal-title {
    font-size: 24px;
    font-weight: 700;
    color: var(--popup-text);
    margin: 0 0 10px 0;
    text-align: center;
  }

  .modal-description {
    font-size: 16px;
    color: var(--popup-secondary);
    margin: 0 0 25px 0;
    text-align: center;
    line-height: 1.5;
  }

  .modal-form {
    display: flex;
    flex-direction: column;
    gap: 15px;
  }

  /* The #emailModal prefix outranks Carrd's own form input styles */
  #emailModal .modal-input {
    padding: 14px 18px;
    border: 2px solid #e5e7eb;
    border-radius: 10px;
    font-size: 16px;
    transition: border-color 0.2s;
    outline: none;
  }

  #emailModal .modal-input:focus {
    border-color: var(--popup-accent);
  }

  .modal-button {
    padding: 14px 24px;
    background: var(--popup-accent);
    color: white;
    border: none;
    border-radius: 10px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.2s, transform 0.1s;
  }

  .modal-button:hover {
    background: #4338ca;
    transform: translateY(-1px);
  }

  .modal-note {
    font-size: 13px;
    color: var(--popup-secondary);
    text-align: center;
    margin: 15px 0 0 0;
  }

  /* Honeypot: real visitors never see or fill this field */
  .modal-hp {
    position: absolute;
    left: -9999px;
  }

  @media (max-width: 480px) {
    .modal-inner {
      padding: 30px 20px;
    }

    .modal-title {
      font-size: 20px;
    }
  }
</style>

<dialog id="emailModal" aria-labelledby="emailModalTitle">
  <div class="modal-inner">
    <button class="modal-close" aria-label="Close"
            onclick="document.getElementById('emailModal').close()">×</button>
    <h2 class="modal-title" id="emailModalTitle">Get Weekly Tips</h2>
    <p class="modal-description">Practical advice for your site, delivered to your inbox every week.</p>
    <form class="modal-form" action="YOUR_FORM_ENDPOINT" method="POST" target="_blank">
      <input type="text" name="website" class="modal-hp" tabindex="-1" autocomplete="off" aria-hidden="true">
      <input type="email" name="email" class="modal-input" placeholder="Enter your email" required>
      <button type="submit" class="modal-button">Subscribe</button>
    </form>
    <p class="modal-note">No spam. Unsubscribe anytime.</p>
  </div>
</dialog>

<script>
  const dlg = document.getElementById('emailModal');

  // Show once per session. The flag is set when the popup is SHOWN,
  // not when it closes, so a visitor who navigates away mid-popup
  // doesn't get ambushed again on the next page.
  if (!sessionStorage.getItem('modalShown')) {
    setTimeout(function () {
      dlg.showModal();
      sessionStorage.setItem('modalShown', 'true');
    }, 3000); /* keep in sync with --popup-delay */
  }

  // Backdrop click closes. The click target is the <dialog> element itself
  // (the .modal-inner wrapper covers the dialog box, so only true backdrop
  // clicks land here).
  dlg.addEventListener('click', function (e) {
    if (e.target === dlg) dlg.close();
  });

  // Bots fill the hidden honeypot field; real visitors never see it.
  dlg.querySelector('form').addEventListener('submit', function (e) {
    if (this.elements.website.value) e.preventDefault();
  });

  // Escape handling is native with <dialog>. No keydown handler needed.
</script>
```

### Opciones de personalización

Para cambiar la espera, actualiza tanto `--popup-delay` (documentación) como la llamada `setTimeout(..., 3000)`. 3000 = 3 segundos. En móvil, 4 a 5 segundos convierten mejor que 1 a 2; la gente aún se está orientando.

Todo funciona con las variables CSS de arriba para los colores: `--popup-accent` es el botón, `--popup-bg` la tarjeta, `--popup-text` el encabezado, `--popup-secondary` el texto de apoyo.

Para conectar tu servicio de email, reemplaza `YOUR_FORM_ENDPOINT` con la URL de acción del formulario de tu proveedor de email. Luego haz coincidir el `name` del campo de email con lo que ese proveedor espera: `email` funciona para Buttondown, Kit usa `email_address` y Mailchimp usa `EMAIL`. Cópialo del HTML del formulario del propio proveedor si tienes dudas; un nombre de campo incorrecto hace que el registro falle en silencio. El formulario abre la página de confirmación del proveedor en una pestaña nueva (`target="_blank"`) para que los visitantes no salgan de tu sitio. Si el endpoint de tu proveedor soporta CORS, puedes hacer `fetch()` y mostrar un agradecimiento en línea. Ese camino depende del proveedor. Verifícalo antes de publicar. Un campo que debes dejar tranquilo: `website` es un honeypot. Los bots lo rellenan, los humanos no, y el script cancela cualquier envío donde no esté vacío.

### Solución de problemas

- **La ventana emergente no aparece en el editor.** Es lo esperado. Carrd no ejecuta el código de los embeds en el builder. Prueba siempre la URL publicada en una ventana de incógnito nueva.
- **No se renderiza nada en absoluto.** Tres comprobaciones: Type está en **Code** (no Iframe), Style está en **Hidden** y tu plan es Pro Standard o superior. Las cuentas Free y Pro Lite descartan el código personalizado en silencio.
- **La ventana se repite en cada página.** La línea `sessionStorage.setItem('modalShown', 'true')` debe ejecutarse en el camino de mostrar (justo después de `showModal()`). Ejecutarla solo en un manejador de cierre no es suficiente. El código de arriba lo hace correctamente. Si lo editaste, comprueba que no la hayas movido.
- **El formulario se envía pero no llega nada a tu ESP.** La URL de acción está mal o incompleta. Compárala carácter a carácter con el endpoint que te da tu proveedor, y revisa el registro de envíos del proveedor antes de asumir que la ventana está rota.
- **El fondo sigue haciendo scroll detrás de la ventana.** `showModal()` no bloquea el scroll por sí solo. Comprueba que la regla `body:has(dialog#emailModal[open])` siga en tu CSS y que el ID coincida con tu diálogo.

<Accordion label="¿Necesitas una versión antigua basada en div para navegadores obsoletos?">
<p><code>&lt;dialog&gt;</code> está soportado en todos los navegadores lanzados desde marzo de 2022. A menos que tengas analíticas que muestren una proporción significativa de navegadores anteriores a 2022, no te molestes.</p>
<p>Si debes soportarlos, construye la capa con dos elementos <code>div</code> anidados y un toggle de clase <code>.active</code>, como usaban las versiones anteriores de esta guía. Tres cosas que añadir para que siga siendo usable:</p>
<p>1. Accesibilidad: <code>role="dialog"</code>, <code>aria-modal="true"</code> y <code>aria-labelledby</code> apuntando al título; mueve el foco al botón de cierre al abrir y restáuralo al cerrar.</p>
<p>2. Bloqueo de scroll: <code>document.body.style.overflow = 'hidden'</code> falla en iOS Safari. Usa ahí el patrón de body con <code>position: fixed</code>.</p>
<p>3. Animaciones: envuelve cada transición y keyframe en <code>@media (prefers-reduced-motion: no-preference)</code> y añade <code>z-index: 9999</code> para que la capa quede por encima del marcado de Carrd.</p>
</Accordion>

---

## Opción 2: Ventana emergente activada por clic

Esta ventana emergente se abre cuando el visitante pulsa un botón. Mejor para detalles de producto, términos, tablas de precios o cualquier cosa demasiado larga para la página principal. Si has usado un [botón flotante de chat de WhatsApp](https://www.bitdoze.com/carrd-whatsapp-button/) en Carrd, el modelo de interacción es el mismo: un activador persistente que el visitante decide pulsar.

La reescritura de abajo usa la Popover API. El resultado es una ventana emergente en Carrd sin JavaScript: el botón activador habla con el popover a través del atributo `popovertarget`, el cierre ligero (clic fuera) es nativo, Escape funciona de forma nativa y el panel se renderiza en la capa superior. Soporte de navegadores: Chrome/Edge 114+, Safari 17+, Firefox 125+ (datos de compatibilidad de MDN, comprobado en septiembre de 2026). Seguro en cualquier navegador evergreen.

<Notice type="info" title="Este embed usa Style: Inline">
El código de abajo incluye un botón visible de "Learn More", así que configura este elemento Embed en <strong>Type: Code, Style: Inline</strong> y arrástralo al punto donde debería aparecer el botón. Un embed Hidden en Body End empujaría el botón debajo de todo tu sitio. El popover en sí sigue abriéndose centrado sobre la página.
</Notice>

```html
<style>
  :root {
    --click-popup-bg: #ffffff;
    --click-popup-overlay: rgba(0, 0, 0, 0.7);
    --click-popup-accent: #10b981;
    --click-popup-text: #111827;
    --click-popup-radius: 20px;
  }

  [popover]#svcModal {
    /* Carrd's CSS reset zeroes div margins; auto re-centers the popover */
    margin: auto;
    text-align: left;
    border: 0;
    border-radius: var(--click-popup-radius);
    max-width: 600px;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
    padding: 0;
    background: var(--click-popup-bg);
    color: var(--click-popup-text);
  }

  [popover]#svcModal::backdrop {
    background: var(--click-popup-overlay);
  }

  @media (prefers-reduced-motion: no-preference) {
    [popover]#svcModal:popover-open {
      animation: slideUp 0.3s ease;
    }

    @keyframes slideUp {
      from {
        opacity: 0;
        transform: translateY(30px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }
  }

  .click-modal-header {
    padding: 25px 30px;
    border-bottom: 1px solid #e5e7eb;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .click-modal-title {
    font-size: 22px;
    font-weight: 700;
    color: var(--click-popup-text);
    margin: 0;
  }

  .click-modal-close {
    width: 36px;
    height: 36px;
    border: none;
    background: #f3f4f6;
    border-radius: 50%;
    cursor: pointer;
    font-size: 22px;
    color: #6b7280;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .click-modal-close:hover {
    background: #e5e7eb;
  }

  .click-modal-body {
    padding: 30px;
    color: #4b5563;
    line-height: 1.7;
  }

  .click-modal-body h3 {
    color: var(--click-popup-text);
    margin: 0 0 15px 0;
    font-size: 18px;
    font-weight: 600;
  }

  .click-modal-body p {
    margin: 0 0 20px 0;
  }

  .click-modal-body ul {
    margin: 0 0 20px 0;
    padding-left: 20px;
    list-style: disc;
  }

  .click-modal-body li {
    margin-bottom: 10px;
  }

  .click-modal-footer {
    padding: 20px 30px;
    border-top: 1px solid #e5e7eb;
    text-align: right;
  }

  .click-modal-btn {
    padding: 12px 28px;
    background: var(--click-popup-accent);
    color: white;
    border: none;
    border-radius: 10px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
  }

  .click-modal-btn:hover {
    opacity: 0.9;
  }

  /* Trigger button: used when the trigger lives inside the embed */
  .popup-trigger {
    padding: 14px 28px;
    background: var(--click-popup-accent);
    color: white;
    border: none;
    border-radius: 10px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.2s;
  }

  .popup-trigger:hover {
    transform: translateY(-2px);
  }
</style>

<!-- Trigger: popovertarget must match the popover id exactly -->
<button class="popup-trigger" type="button" popovertarget="svcModal">Learn More</button>

<div id="svcModal" popover aria-label="Service details">
  <div class="click-modal-header">
    <h2 class="click-modal-title">Service Details</h2>
    <button class="click-modal-close" aria-label="Close"
            popovertarget="svcModal" popovertargetaction="hide">×</button>
  </div>
  <div class="click-modal-body">
    <h3>What's Included</h3>
    <ul>
      <li>Full website design and development</li>
      <li>Mobile-responsive layout</li>
      <li>SEO optimization</li>
      <li>2 rounds of revisions</li>
      <li>30 days of support after launch</li>
    </ul>
    <p>Turnaround time is typically 2-3 weeks depending on project complexity. We'll discuss your specific needs during our initial consultation.</p>
  </div>
  <div class="click-modal-footer">
    <button class="click-modal-btn" popovertarget="svcModal" popovertargetaction="hide">Got It</button>
  </div>
</div>
```

Sin bloque `<script>`. El comportamiento por defecto de `popover` (`popover="auto"`) te da cierre ligero, Escape y renderizado en capa superior por sí solo. Es lo más ligero que puede ser un diálogo en Carrd.

### Cómo añadir el botón activador

Tres formas de conectar el activador, ordenadas por cuánto confío en ellas:

1\. Botón activador dentro del embed (Pro Standard, funciona en todas partes). El `<button popovertarget="svcModal">` del código de arriba forma parte del marcado del embed. Pega todo el bloque en un embed Inline colocado donde deba ir el botón, publica y listo. Cero JavaScript, cero requisito de Pro Plus.

2\. Botón nativo de Carrd + Events (Pro Plus). ¿Quieres el estilo de botón propio de Carrd? En Pro Plus, añade un elemento Button nativo, pon su URL en `browser:none` y luego abre Settings → Events → On Click y ejecuta:

```js
document.getElementById('svcModal').showPopover();
```

Para este camino, borra la línea `<button class="popup-trigger" ...>` del embed. Sin marcado visible, cambia el embed a Hidden, Body End para que el popover no quede atado a una sección. Olvida la idea de añadir `popovertarget` al botón nativo como atributo personalizado: Carrd renderiza los botones como enlaces `<a>`, y `popovertarget` solo funciona en elementos `<button>` e `<input>`. El evento On Click es el camino documentado de Carrd y el más limpio si tienes el plan.

3\. URLs `javascript:`, no documentadas. Úsalas bajo tu propio riesgo. Poner `javascript:document.getElementById('svcModal').showPopover()` en el campo URL de un botón puede funcionar, pero `javascript:` no es uno de los tipos de URL documentados de Carrd (la lista documentada cubre site/email/phone/sms/skype/browser/section/scroll-point/clipboard/copy a septiembre de 2026).

<Notice type="warning" title="Las URLs javascript: no están documentadas">
Carrd puede eliminar o bloquear las URLs <code>javascript:</code> sin aviso ni entrada en el changelog. Si usas este truco, pruébalo en el sitio en vivo antes de compartir el enlace, y vuelve a probarlo tras cada actualización de Carrd. Prefiere el camino 1 o 2.
</Notice>

Si el activador no hace nada, `popovertarget` y el `id` del popover deben coincidir exactamente, incluidas las mayúsculas. `popovertarget="svcModal"` hace pareja con `id="svcModal"`. Un solo error de escritura y el botón queda inerte.

---

## Opción 3: Ventana emergente de intención de salida

Esta ventana se dispara cuando un visitante de escritorio mueve el cursor hacia el chrome del navegador. La última oportunidad de captar su atención antes de que se cierre la pestaña. Buena para un descuento o un lead magnet.

La detección usa `mouseleave` en el elemento document con una guarda `clientY <= 0` (el viejo enfoque `mouseout` + `e.toElement` se apoyaba en una propiedad obsoleta). La tarjeta de oferta mantiene su diseño con degradado. La bandera `exitModalShown` se establece cuando la ventana se muestra y se comprueba antes de mostrarla, así que se dispara como máximo una vez por sesión.

```html
<style>
  :root {
    --exit-popup-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    --exit-popup-card: #ffffff;
    --exit-popup-text: #1f2937;
  }

  .exit-modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.8);
    display: none;
    justify-content: center;
    align-items: center;
    z-index: 9999;
    padding: 20px;
  }

  .exit-modal-overlay.active {
    display: flex;
  }

  .exit-modal-content {
    background: var(--exit-popup-bg);
    border-radius: 24px;
    max-width: 500px;
    width: 100%;
    padding: 50px 40px;
    position: relative;
    text-align: center;
  }

  @media (prefers-reduced-motion: no-preference) {
    .exit-modal-overlay.active .exit-modal-content {
      animation: bounceIn 0.4s ease;
    }

    @keyframes bounceIn {
      0% {
        opacity: 0;
        transform: scale(0.5);
      }
      70% {
        transform: scale(1.05);
      }
      100% {
        opacity: 1;
        transform: scale(1);
      }
    }
  }

  .exit-modal-close {
    position: absolute;
    top: 15px;
    right: 15px;
    width: 36px;
    height: 36px;
    border: none;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 50%;
    cursor: pointer;
    font-size: 20px;
    color: white;
  }

  .exit-modal-close:hover {
    background: rgba(255, 255, 255, 0.3);
  }

  .exit-modal-emoji {
    font-size: 60px;
    margin-bottom: 20px;
  }

  .exit-modal-title {
    font-size: 28px;
    font-weight: 700;
    color: white;
    margin: 0 0 15px 0;
  }

  .exit-modal-description {
    font-size: 18px;
    color: rgba(255, 255, 255, 0.9);
    margin: 0 0 30px 0;
    line-height: 1.6;
  }

  .exit-modal-cta {
    padding: 16px 40px;
    background: white;
    color: #667eea;
    border: none;
    border-radius: 12px;
    font-size: 18px;
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.2s;
    margin-bottom: 15px;
  }

  .exit-modal-cta:hover {
    transform: scale(1.05);
  }

  .exit-modal-skip {
    background: none;
    border: none;
    color: rgba(255, 255, 255, 0.7);
    font-size: 14px;
    cursor: pointer;
    text-decoration: underline;
  }

  .exit-modal-skip:hover {
    color: white;
  }

  @media (max-width: 480px) {
    .exit-modal-content {
      padding: 40px 25px;
    }

    .exit-modal-title {
      font-size: 24px;
    }
  }
</style>

<div class="exit-modal-overlay" id="exitModal" role="dialog" aria-modal="true" aria-labelledby="exitModalTitle">
  <div class="exit-modal-content">
    <button class="exit-modal-close" id="exitModalClose" aria-label="Close" onclick="closeExitModal()">×</button>
    <div class="exit-modal-emoji" aria-hidden="true">👋</div>
    <h2 class="exit-modal-title" id="exitModalTitle">Wait! Before You Go...</h2>
    <p class="exit-modal-description">Get 20% off your first order when you sign up for our newsletter.</p>
    <button class="exit-modal-cta" onclick="closeExitModal(); window.location.href='#signup'">Claim My Discount</button>
    <br>
    <button class="exit-modal-skip" onclick="closeExitModal()">No thanks, I'll pay full price</button>
  </div>
</div>

<script>
  let exitShown = false;

  function showExitModal() {
    var overlay = document.getElementById('exitModal');
    overlay.classList.add('active');
    document.body.style.overflow = 'hidden';
    sessionStorage.setItem('exitModalShown', 'true'); // set on SHOW
    exitShown = true;
    document.getElementById('exitModalClose').focus();
  }

  function closeExitModal() {
    document.getElementById('exitModal').classList.remove('active');
    document.body.style.overflow = '';
  }

  // Click on the overlay backdrop closes
  document.getElementById('exitModal').addEventListener('click', function (e) {
    if (e.target === this) closeExitModal();
  });

  // Escape only acts when the modal is open
  document.addEventListener('keydown', function (e) {
    if (e.key === 'Escape' && document.getElementById('exitModal').classList.contains('active')) {
      closeExitModal();
    }
  });

  // Exit intent: cursor leaves through the top of the viewport (desktop only)
  document.documentElement.addEventListener('mouseleave', function (e) {
    if (e.clientY <= 0 && !e.relatedTarget && !exitShown && !sessionStorage.getItem('exitModalShown')) {
      showExitModal();
    }
  });
</script>
```

El botón "Claim My Discount" cierra la ventana y salta a `#signup`. Cámbialo por el nombre de tu sección de registro o punto de scroll (una sección llamada `offer` se enlaza como `#offer`).

Este es un truco solo para escritorio. Los teléfonos y tablets no tienen evento de salida del ratón, así que una ventana pura de intención de salida en Carrd es código muerto en móvil. Está bien para ofertas pensadas primero para escritorio. Si el tráfico móvil importa, añade la alternativa de abajo.

### Alternativa para móvil: activación por profundidad de scroll

Para los visitantes móviles, la intención se manifiesta como scroll, no como acercarse al botón de cerrar. Pega este bloque en el mismo embed, debajo de la etiqueta de cierre `</script>` existente (tiene sus propias etiquetas `<script>`, así que no lo anides dentro del primero). Se dispara una vez cuando el visitante supera el 50 % de la página y respeta la misma bandera `exitModalShown`:

```html
<script>
  // Mobile fallback: show once at 50% scroll depth
  window.addEventListener('scroll', function () {
    if (exitShown || sessionStorage.getItem('exitModalShown')) return;
    var scrolled = window.scrollY / (document.body.scrollHeight - window.innerHeight);
    if (scrolled > 0.5) {
      showExitModal();
    }
  }, { passive: true });
</script>
```

Ajusta el umbral `0.5` a la longitud de tu página. En una página de ventas larga, 0.7 suele ser menos molesto; en un sitio de una sola página corto, 0.4. La bandera `{ passive: true }` evita que el manejador de scroll perjudique el rendimiento del scroll.

**Verifícalo:** abre el sitio en un escritorio y en un teléfono real. En escritorio, mover el cursor fuera por la parte superior de la ventana dispara la ventana exactamente una vez. En móvil, hacer scroll más allá de la mitad la dispara exactamente una vez. Ninguna se repite en la misma sesión.

---

## ¿De verdad necesitas código personalizado?

Antes de pegar nada, sé honesto sobre lo que necesitas. Una "ventana emergente" en sentido amplio (contenido que aparece sobre la página) no siempre requiere un elemento Embed.

![Flujo de decisión: si solo necesitas un registro o una confirmación, usa una Sección de Carrd, un Formulario de Registro nativo o un widget; si necesitas activadores por tiempo, clic o salida, usa las tres opciones para copiar y pegar](@assets/images/26/01/carrd-popup-decision-flow.svg)

<ListCheck>
<ul>
<li>Carrd Sections para capas a pantalla completa y confirmaciones estilo modal con cero código personalizado (conviene confirmar la disponibilidad en el plan gratis de tu cuenta antes de apostar por ello)</li>
<li>Carrd Signup Forms (Pro Standard+) con integraciones nativas a 20 plataformas de email, así que un botón CTA que enlaza a una sección de formulario es mejor que pelearse con endpoints</li>
<li>Widgets de ventanas emergentes de terceros (Common Ninja, Smartarget y similares) insertados a través del mismo elemento Embed. Cero programación, JavaScript más pesado, normalmente freemium</li>
</ul>
</ListCheck>

Para contenido tipo FAQ en concreto, un modal completo suele ser la herramienta equivocada. Un patrón de despliegue es más ligero y mejor para el SEO. Mira cómo [añadir FAQs de acordeón a Carrd](https://www.bitdoze.com/es/anadir-acordeon-faq-carrd/), o consigue el [plugin de acordeón para Carrd](https://go.carrdme.com/accordion) o el [plugin de pestañas para Carrd](https://go.carrdme.com/tabs) si quieres el widget sin el código.

Mi opción por defecto: si quieres control por tiempo, clic o intención de salida, el código de este artículo sigue siendo el camino más ligero: un embed, sin script de terceros, sin cuota mensual de widget. Si solo necesitas un momento de registro o una capa de confirmación, usa una Sección o un Formulario de Registro nativo y sáltate el código personalizado por completo.

## Conexión con servicios de email

La Opción 1 envía a `YOUR_FORM_ENDPOINT`. Reemplázalo con la URL de acción real del formulario de tu proveedor. Aquí está el estado actual de los tres sobre los que más me preguntan, más el atajo nativo.

<Tabs>
<Tab name="Kit">

Kit (antes ConvertKit, renombrado en 2024) acepta envíos de formulario en una URL de acción simple. `convertkit.com` redirige a `kit.com`, y la app vive en `app.kit.com`. Las URL de acción de los formularios HTML embed siguen este patrón:

```text
https://app.kit.com/forms/FORM_ID/subscriptions
```

Copia el HTML del formulario desde tu panel de Kit (Grow → Landing Pages & Forms → tu formulario → Embed → HTML) y toma el valor de `action`. La ruta exacta de clics cambia de vez en cuando. Si el menú no coincide, busca "embed form" en la documentación de Kit. Una cosa que no pude confirmar: si el embed HTML en bruto está disponible en el plan gratis de Kit o solo en los de pago. Revisa tu cuenta antes de construir en torno a ello.

</Tab>
<Tab name="Buttondown">

Usa el dominio actual. `buttondown.email` aún redirige, pero no construyas sobre una redirección:

```text
https://buttondown.com/api/emails/embed-subscribe/USERNAME
```

Cambia `USERNAME` por tu nombre de usuario de Buttondown. Esa es toda la integración; sin clave API en el formulario.

</Tab>
<Tab name="Mailchimp">

Audience → Signup forms → Create embedded form. Copia el HTML del formulario y toma de él el atributo `action`. Mailchimp ahora soporta campos de email más SMS en los formularios embed.

Una advertencia que vale la pena repetir de la propia documentación de Mailchimp: si empiezas a ver registros falsos, **regenera el código del formulario embed** y reemplázalo en tu sitio. El código embed nuevo lleva un token reCAPTCHA que funciona; el código viejo puede ser explotado.

</Tab>
<Tab name="Formulario de Registro nativo de Carrd">

Puedes saltarte los endpoints por completo. El elemento Signup Form integrado de Carrd (Pro Standard+) envía directamente a 20 plataformas: Kit, Buttondown, Mailchimp, MailerLite, EmailOctopus, Brevo, beehiiv, Ghost, HubSpot, Klaviyo, Loops, Mailjet, Omnisend, Resend, Sender, SendFox, SendGrid, Sendy, ActiveCampaign y GetResponse. Sin pelearse con la URL `action`, sin adivinar nombres de campos.

Si vas por este camino, la ventana emergente se convierte en un CTA que abre o enlaza a una sección de formulario de registro. Combina la Opción 2 con un formulario en lugar de la Opción 1.

Opciones de ESP económicas con las que Carrd se integra de forma nativa: [EmailOctopus](https://go.bitdoze.com/emailoctopus), [MailerLite](https://go.bitdoze.com/mailerlite) y [Sender](https://go.bitdoze.com/sender) (el plan gratis ha incluido 15.000 emails/mes; confírmalo en su sitio).

</Tab>
</Tabs>

Nota de costes: el código de la ventana emergente es gratis; el ESP es donde aparece el coste. El nivel gratis de Sender ha cubierto 15.000 emails/mes (revisa de nuevo su página de precios). EmailOctopus y MailerLite cobran aproximadamente entre 10 y 20 $/mes una vez que superas los niveles gratis. Revisa sus páginas de precios al publicar, porque cambian.

Si prefieres un simple formulario de contacto antes que una lista de email, la misma mecánica de embed también lo hace posible. Mira [cómo añadir un formulario de contacto a un sitio web estático](https://www.bitdoze.com/add-contact-form-static-websites/) para opciones de endpoints que funcionan con Carrd.

**Nota sobre el RGPD (no es asesoría legal):** un simple formulario de captura de email con un propósito claro generalmente está bien según las normas de la UE. El panorama de consentimiento cambia cuando añades scripts de analítica o píxeles de seguimiento junto a la ventana emergente. Ahí es donde entran las obligaciones de cookies y consentimiento. Si recibes visitantes de la UE y usas cualquier tipo de seguimiento, [añade un aviso de cookies a tu sitio Carrd](https://www.bitdoze.com/add-cookie-notice-carrd/) y mantén la ventana emergente libre de rastreadores de terceros.

## Verificación, modos de fallo y rollback

<Notice type="info" title="Prueba en el sitio publicado">
Carrd no ejecuta el código de los embeds en la vista previa del builder, así que solo la URL en vivo te dice algo. Cada comprobación de abajo se hace contra el sitio publicado, en una ventana de incógnito (<code>sessionStorage</code> limpio), tanto en escritorio como en un teléfono real.
</Notice>

Tras publicar, recorre esta lista de comprobación:

<ListCheck>
<ul>
<li>Abre la URL en vivo en incógnito y confirma que la ventana correcta se dispara con su activador (espera, clic, salida o profundidad de scroll)</li>
<li>Pulsa Escape. La ventana debería cerrarse (las Opciones 1 y 2 lo hacen de forma nativa)</li>
<li>Haz clic fuera de la tarjeta. Un clic en el fondo debería cerrarla</li>
<li>Ciérrala y recarga en la misma pestaña. NO debería reaparecer (el límite por sesión funciona)</li>
<li>Envía el formulario con una dirección real y confirma que llega a tu panel del ESP</li>
<li>Repite la prueba del activador en un teléfono real, sobre todo la alternativa de scroll de la Opción 3</li>
<li>Si usaste un activador con URL `javascript:`, vuelve a probarlo en el sitio en vivo antes de compartir el enlace</li>
</ul>
</ListCheck>

Cosas que se rompen, y su arreglo:

- **La vista previa y el sitio en vivo no coinciden.** Confía siempre en la URL en vivo. Vuelve a publicar si el editor muestra cambios que el sitio en vivo no tiene.
- **El embed no se renderiza.** Type no está en Code, Style está mal (Hidden, Body End para las Opciones 1 y 3; Inline para la Opción 2), o tu plan es inferior a Pro Standard. En ese orden.
- **La ventana aparece detrás del contenido de la página.** Solo es un problema para las versiones antiguas con div. Necesitan `z-index: 9999`. Las versiones con `<dialog>` y popover viven en la capa superior y se saltan toda esta clase de bugs.
- **La misma opción pegada dos veces, ambas rotas.** Colisiones de IDs. Renombra cada ID, clase, variable y nombre de función del segundo bloque, o mantén una ventana por página.
- **La ventana de salida nunca se dispara en teléfonos.** Es lo esperado. No hay ratón. Añade la alternativa de profundidad de scroll.
- **El fondo hace scroll detrás de una ventana basada en div en iOS.** El bloqueo con `overflow: hidden` en el body no siempre aguanta en iOS Safari. Usa el patrón de body con `position: fixed` en el código antiguo, y prueba en un iPhone real.
- **Registros falsos en Mailchimp.** Regenera el código del formulario embed para que reCAPTCHA funcione, luego reemplaza el endpoint.
- **Un botón activador no hace nada.** Para popovers, `popovertarget` debe coincidir exactamente con el `id`. Para URLs `javascript:`, asume que Carrd la ignoró. Usa un botón dentro del embed o los Events de Pro Plus en su lugar.

Para quitar la ventana (rollback), borra el elemento Embed en el builder de Carrd y vuelve a publicar. No hay archivos de tema, ni JavaScript global, nada más que limpiar. Esa es la belleza del enfoque de embed. Si estabas probando en local, ten en cuenta que las claves de `sessionStorage` como `modalShown` y `exitModalShown` persisten por pestaña; usa incógnito para pruebas limpias o bórralas desde DevTools → Application → Session Storage. Solo revierte la conexión con el ESP si creaste una lista dedicada para la ventana.

## Consejos para ventanas emergentes efectivas

No seas molesto. Muestra la ventana una vez por sesión, no en cada carga de página. Todo el código de arriba usa `sessionStorage` para evitar ventanas repetidas.

Limita la frecuencia con cabeza. `sessionStorage` = una vez por sesión (lo que usa el código). Para ofertas insistentes, `localStorage` más una marca de expiración de 7 días te da una vez por semana. Menos impresiones, menos irritación, conversión similar.

Facilita el cierre. El botón de cerrar debería ser obvio. Deja que la gente haga clic fuera para descartarla. Soporta la tecla Escape. Las Opciones 1 y 2 tienen las tres gratis.

Aporta valor. Nadie quiere registrarse para recibir "novedades". Ofrece algo concreto: un descuento, una guía gratis, contenido exclusivo.

Combina ofertas con urgencia. Un descuento convierte mejor con una fecha límite al lado. Coloca un [temporizador de cuenta regresiva con estilo](https://www.bitdoze.com/es/estilos-cuenta-regresiva-carrd/) en el cuerpo de la ventana o en la sección a la que enlaza.

Prueba en móvil. Algunos estilos de ventana no funcionan bien en pantallas pequeñas. Revisa tu diseño en teléfonos reales, no solo en la vista previa responsive del editor.

Considera el momento. Las ventanas inmediatas resultan agresivas. Esperar 3-5 segundos o activarlas con scroll suele funcionar mejor.

Respeta los valores de accesibilidad. Mantén los envoltorios `prefers-reduced-motion` alrededor de las animaciones (ya están en el código) y soporta siempre Escape más clic fuera. Las versiones con `<dialog>` y popover manejan el comportamiento del foco de forma nativa.

## Preguntas frecuentes

<Accordion label="¿Carrd tiene ventanas emergentes integradas?" group="faq" expanded="true">
No. Carrd no incluye ningún elemento nativo de ventana emergente o modal. El changelog visible hasta septiembre de 2026 (Elements Panel, iframe Framing, URLs copy:, plantillas, fuentes, iconos) no tiene nada relacionado con ventanas emergentes. El elemento Embed es la forma de conseguir una. Para momentos simples de registro o confirmación, las Carrd Sections y los Signup Forms nativos cubren el terreno sin código.
</Accordion>

<Accordion label="¿Qué plan de Carrd necesito para ventanas emergentes?" group="faq">
Pro Standard (19 $/año, 10 sitios) es el mínimo. Es el primer nivel con Embeds (código personalizado). Las cuentas Free y Pro Lite (9 $/año) no pueden añadir código personalizado en absoluto. Pro Plus (49 $/año, 25 sitios) añade Advanced Settings: eventos On Click en botones, IDs y atributos personalizados, visibilidad por elemento. Precios verificados en septiembre de 2026; las variantes con más sitios cuestan más.
</Accordion>

<Accordion label="¿Las ventanas emergentes de Carrd funcionan en móvil?" group="faq">
Las ventanas con temporizador y las activadas por clic funcionan bien en móvil. Una espera es una espera, un toque es un clic. La intención de salida es solo para escritorio, porque los teléfonos no tienen evento de salida del ratón. Usa la alternativa de profundidad de scroll de la Opción 3 para captar a los visitantes móviles al 50 % de scroll.
</Accordion>

<Accordion label="¿Es seguro usar javascript: en la URL de un botón de Carrd?" group="faq">
No está documentado y por tanto no es seguro depender de ello. Los tipos de URL documentados de Carrd cubren site, email, phone, sms, skype, acciones de browser, secciones, puntos de scroll, clipboard y copy. `javascript:` no está entre ellos (comprobado en septiembre de 2026). Puede funcionar hoy y romperse en silencio mañana. Usa un botón activador dentro del embed (funciona en Pro Standard), o los Events → On Click de Pro Plus. Si aún quieres el truco de `javascript:`, verifícalo primero en tu sitio en vivo y vuelve a probarlo tras cada actualización de Carrd.
</Accordion>

## Conclusión

Las ventanas emergentes no son malvadas. Simplemente se suelen usar mal. Un modal bien diseñado que aparece en el momento adecuado y ofrece valor real puede hacer crecer tu lista de email sin molestar a los visitantes.

Ahora tienes tres tipos de ventana emergente: captura de email con temporizador sobre `<dialog>`, activada por clic sobre la Popover API, e intención de salida con alternativa de scroll para móvil. Todo código gratis para copiar y pegar, todo muy por debajo del tamaño de las viejas versiones basadas en div. Elige una, personaliza los colores y los textos, y recuerda: menos es más. Una ventana bien pensada supera a tres agresivas.

Una vez que la ventana esté en vivo, sigue con más mejoras de código personalizado en Carrd como [añadir un botón de volver arriba a Carrd](https://www.bitdoze.com/carrd-back-to-top-button/), o explora el catálogo completo de plugins y tutoriales en [carrdme.com](https://carrdme.com/).

<Button link="https://go.bitdoze.com/carrd" text="Crea tu sitio en Carrd" />