Ir al contenido

Rendering surfaces

¿Podemos mostrar la encuesta en un BottomSheet o una página propia en lugar de un modal?

Sí. El SDK renderiza dentro de cualquier elemento del DOM al que le apuntes — no dibuja un modal, drawer ni bottom sheet por sí mismo. Eso hace trivial empotrarla dentro de la superficie que tu producto ya use para flujos similares.

El único contrato es: proporciona un elemento con un id, pasa ese id a form.generate(...) y el SDK renderiza dentro.

<div id="survey-root"></div>
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
await form.generate("survey-root");

Debajo, los patrones de superficie más comunes.


La superficie más simple — una ruta entera en tu SPA.

// React
function FeedbackPage() {
useEffect(() => {
magicfeedback.init({ env: "prod" });
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
form.generate("survey-root", { addButton: true, addSuccessScreen: true });
}, []);
return <div id="survey-root" />;
}

Buena para encuestas NPS, encuestas largas, flujos post-compra, URLs dedicadas tipo /feedback.


Renderiza dentro del componente modal que ya tenga tu design system. Al SDK le da igual qué librería uses.

function FeedbackModal({ open, onClose }) {
useEffect(() => {
if (!open) return;
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
form.generate("survey-root", {
addButton: true,
addSuccessScreen: true,
questionFormat: "slim",
afterSubmitEvent: ({ completed }) => {
if (completed) onClose();
},
});
}, [open]);
return (
<Dialog open={open} onClose={onClose}>
<DialogBody>
<div id="survey-root" />
</DialogBody>
</Dialog>
);
}

questionFormat: "slim" mantiene cada paso compacto dentro de un modal.


Mismo patrón — el contenedor vive dentro del drawer.

<Drawer open={open} side="right" onClose={close}>
<div id="survey-root" />
</Drawer>

Útil para feedback inline en producto, encuestas contextuales, prompts tipo “¿Qué podemos mejorar?”.


Un bottom sheet con apariencia nativa es solo un contenedor del DOM estilado para subir desde abajo. Usa cualquier librería (vaul, react-modal-sheet, framer-motion) o monta el tuyo.

import { Drawer } from "vaul";
function FeedbackBottomSheet({ open, onClose }) {
useEffect(() => {
if (!open) return;
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
form.generate("survey-root", { questionFormat: "slim", addButton: true });
}, [open]);
return (
<Drawer.Root open={open} onOpenChange={(v) => !v && onClose()}>
<Drawer.Portal>
<Drawer.Overlay />
<Drawer.Content>
<div id="survey-root" />
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}

Para bottom sheets puramente nativos en React Native, mira React Native — ahí la encuesta corre dentro de un WebView colocado dentro del bottom sheet.


Empótrala como parte de una página más grande (p. ej. una sección de feedback al final de la página de éxito de checkout).

<main>
<h1>¡Gracias por tu compra!</h1>
<p>Ya que estás aquí, nos encantaría tu feedback.</p>
<section>
<div id="survey-root"></div>
</section>
</main>
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
await form.generate("survey-root", { addButton: true });

En cualquier sitio donde tu producto ya tenga contenido anidado, la encuesta puede ser un panel más.

<Tabs>
<TabPanel value="overview"></TabPanel>
<TabPanel value="feedback">
<div id="survey-root" />
</TabPanel>
</Tabs>

Monta el formulario cuando el panel se active, no en la carga inicial — si no, generarías el formulario en un contenedor oculto.


Si necesitas más de una encuesta en la misma página, usa ids de contenedor e instancias distintas.

const a = magicfeedback.form("APP_ID", "PUBLIC_KEY");
const b = magicfeedback.form("OTHER_APP_ID", "OTHER_PUBLIC_KEY");
await a.generate("survey-root-a");
await b.generate("survey-root-b");

Como el SDK renderiza directamente dentro del contenedor, la forma más limpia de “destruir” una encuesta es quitar el contenedor del DOM (o vaciarlo). En React, ocurre automáticamente cuando el componente host se desmonta.

useEffect(() => {
const form = magicfeedback.form("APP_ID", "PUBLIC_KEY");
form.generate("survey-root");
return () => {
// El contenedor lo elimina React cuando este componente se desmonta.
// No hace falta nada más.
};
}, []);

Si vuelves a renderizar la encuesta en el mismo contenedor, llama de nuevo a generate() — por defecto el SDK reemplaza el contenido del contenedor.


SuperficieBuena paraNotas
Página dedicadaEncuestas largas, NPS, flujos post-compraUsa questionFormat: "standard".
ModalFeedback rápido en mitad de sesión, tras un eventoUsa questionFormat: "slim".
Drawer / panelFeedback contextual dentro de una pantalla existenteIgual que el modal.
Bottom sheetMóvil web, micro-encuestas con sensación nativaUsa "slim" y encuestas cortas.
Sección inlineEncuestas “ya que estás aquí” tras una acción principalMantenla corta para evitar fricción.
Paso de wizardEncuestas dentro de un onboarding o flujo guiadoMonta al activar el panel.
React NativeApps nativasUsa un WebView — mira la referencia.