Ventana Modal Emergente en Carrd: Cómo Añadir Una a Tu Sitio (2026)
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.
Actualizado Publicado 95 min de lectura

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 mantiene las cosas simples a propósito. Está bien. Un elemento Embed es todo lo que necesitas aquí.
Crea con CarrdAlgunos tutoriales de Carrd:
- Añadir scroll suave a Carrd
- Añadir un slider de testimonios a Carrd
- Añadir un alternador de modo oscuro a Carrd
- Añadir un menú flotante a Carrd
- Añadir un menú lateral a Carrd
- Añadir una cabecera fija a Carrd
La lista completa con plugins, temas y tutoriales de Carrd la puedes encontrar en mi sitio web carrdme.com.
Por qué añadir ventanas emergentes a tu sitio Carrd
Las ventanas emergentes sirven para tareas concretas:
- Captura de emails. Haz crecer tu lista de newsletter sin dedicar espacio destacado de la página a formularios de registro.
- Anuncios. Informa a los visitantes sobre ofertas, nuevos productos o novedades que vale la pena conocer.
- Lightboxes de imágenes. Muestra versiones más grandes de imágenes de portafolio o fotos de productos.
- Intención de salida. Capta a los visitantes antes de que se vayan con una última oferta.
- 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?
Necesitas Carrd Pro Standard (19 $/año) o superior
Los embeds (el elemento que hace posible cualquier ventana modal emergente en Carrd) requieren Pro Standard (19 $/año, 10 sitios) 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á. Pro Plus (49 $/año, 25 sitios) añade Advanced Settings: IDs y atributos personalizados, además de eventos On Click en los botones, que te dan botones activadores más limpios para la Opción 2.
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.
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.
Ver planes de CarrdCó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

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).
Type debe ser Code
Establece Type en Code, 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 <style> y <script> aquí.
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.
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.
- Hacer crecer una newsletter → Opción 1, ventana emergente de captura de email con temporizador (se muestra tras una espera)
- Mostrar detalles, términos o una oferta bajo demanda → Opción 2, ventana emergente activada por clic
- Oferta de última oportunidad en escritorio → Opción 3, ventana emergente de intención de salida (con alternativa de scroll para móvil)
No mezcles opciones a ciegas
Cada opción trae sus propios IDs de elemento (emailModal, svcModal, exitModal), 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.
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.
<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 deshowModal()). 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 reglabody:has(dialog#emailModal[open])siga en tu CSS y que el ID coincida con tu diálogo.
¿Necesitas una versión antigua basada en div para navegadores obsoletos?
<dialog> 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.
Si debes soportarlos, construye la capa con dos elementos div anidados y un toggle de clase .active, como usaban las versiones anteriores de esta guía. Tres cosas que añadir para que siga siendo usable:
1. Accesibilidad: role=“dialog”, aria-modal=“true” y aria-labelledby apuntando al título; mueve el foco al botón de cierre al abrir y restáuralo al cerrar.
2. Bloqueo de scroll: document.body.style.overflow = ‘hidden’ falla en iOS Safari. Usa ahí el patrón de body con position: fixed.
3. Animaciones: envuelve cada transición y keyframe en @media (prefers-reduced-motion: no-preference) y añade z-index: 9999 para que la capa quede por encima del marcado de Carrd.
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 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.
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 Type: Code, Style: Inline 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.
<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:
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).
Las URLs javascript: no están documentadas
Carrd puede eliminar o bloquear las URLs javascript: 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.
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.
<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:
<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.
- 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)
- 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
- 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
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, o consigue el plugin de acordeón para Carrd o el plugin de pestañas para Carrd 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.
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:
https://app.kit.com/forms/FORM_ID/subscriptionsCopia 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.
Buttondown
Usa el dominio actual. buttondown.email aún redirige, pero no construyas sobre una redirección:
https://buttondown.com/api/emails/embed-subscribe/USERNAMECambia USERNAME por tu nombre de usuario de Buttondown. Esa es toda la integración; sin clave API en el formulario.
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.
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, MailerLite y Sender (el plan gratis ha incluido 15.000 emails/mes; confírmalo en su sitio).
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 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 y mantén la ventana emergente libre de rastreadores de terceros.
Verificación, modos de fallo y rollback
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 (sessionStorage limpio), tanto en escritorio como en un teléfono real.
Tras publicar, recorre esta lista de comprobación:
- 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)
- Pulsa Escape. La ventana debería cerrarse (las Opciones 1 y 2 lo hacen de forma nativa)
- Haz clic fuera de la tarjeta. Un clic en el fondo debería cerrarla
- Ciérrala y recarga en la misma pestaña. NO debería reaparecer (el límite por sesión funciona)
- Envía el formulario con una dirección real y confirma que llega a tu panel del ESP
- Repite la prueba del activador en un teléfono real, sobre todo la alternativa de scroll de la Opción 3
- Si usaste un activador con URL
javascript:, vuelve a probarlo en el sitio en vivo antes de compartir el enlace
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: hiddenen el body no siempre aguanta en iOS Safari. Usa el patrón de body conposition: fixeden 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,
popovertargetdebe coincidir exactamente con elid. Para URLsjavascript:, 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 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
¿Carrd tiene ventanas emergentes integradas?
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.
¿Qué plan de Carrd necesito para ventanas emergentes?
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.
¿Las ventanas emergentes de Carrd funcionan en móvil?
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.
¿Es seguro usar javascript: en la URL de un botón de Carrd?
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.
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, o explora el catálogo completo de plugins y tutoriales en carrdme.com.
Crea tu sitio en Carrd

