React
Compatibilidad
Sección titulada «Compatibilidad»El SDK es una librería de navegador. Depende de window, document, navigator y localStorage, y renderiza directamente dentro del elemento del DOM cuyo id le pases. Funciona en cualquier app React que corra en el navegador (Vite, CRA, Next.js, Remix, etc.).
Para frameworks con SSR (Next.js App Router, Remix), instancia el SDK solo en el cliente — dentro de useEffect o desde un componente 'use client'.
Instalación
Sección titulada «Instalación»npm install @magicfeedback/nativeImporta la hoja de estilos una vez, en el punto de entrada de tu app:
// p. ej. main.tsx, _app.tsx, layout.tsximport "@magicfeedback/native/dist/styles/magicfeedback-default.css";Componente básico
Sección titulada «Componente básico»El patrón mínimo: un contenedor <div> con un id estable y un useEffect que llama a init y generate una sola vez.
import { useEffect } from "react";import magicfeedback from "@magicfeedback/native";
export function FeedbackSurvey() { 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" />;}Hook reutilizable
Sección titulada «Hook reutilizable»Si montas la encuesta en más de un sitio, envuelve la configuración en un hook:
import { useEffect } from "react";import magicfeedback from "@magicfeedback/native";import type { generateFormOptions } from "@magicfeedback/native/dist/types/src/models/types";
export function useMagicFeedbackForm( containerId: string, appId: string, publicKey: string, options?: generateFormOptions,) { useEffect(() => { magicfeedback.init({ env: "prod" }); const form = magicfeedback.form(appId, publicKey); form.generate(containerId, options); }, [containerId, appId, publicKey]);}function FeedbackPage() { useMagicFeedbackForm("survey-root", "APP_ID", "PUBLIC_KEY", { addButton: true, questionFormat: "slim", });
return <div id="survey-root" />;}Next.js (App Router)
Sección titulada «Next.js (App Router)»"use client";
import { useEffect } from "react";import magicfeedback from "@magicfeedback/native";import "@magicfeedback/native/dist/styles/magicfeedback-default.css";
export function FeedbackSurvey() { useEffect(() => { magicfeedback.init({ env: "prod" }); const form = magicfeedback.form( process.env.NEXT_PUBLIC_MF_APP_ID!, process.env.NEXT_PUBLIC_MF_PUBLIC_KEY!, ); form.generate("survey-root", { addButton: true }); }, []);
return <div id="survey-root" />;}Renderizar en un modal
Sección titulada «Renderizar en un modal»El SDK no dibuja el modal — lo hace tu design system. Monta la encuesta solo cuando el modal se abre.
import { useEffect } from "react";import magicfeedback from "@magicfeedback/native";
export function FeedbackModal({ open, onClose,}: { open: boolean; onClose: () => void;}) { 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]);
if (!open) return null;
return ( <Dialog onClose={onClose}> <div id="survey-root" /> </Dialog> );}Mira Rendering surfaces para más patrones (drawer, bottom sheet, página dedicada).
Eventos de ciclo de vida
Sección titulada «Eventos de ciclo de vida»useEffect(() => { const form = magicfeedback.form("APP_ID", "PUBLIC_KEY"); form.generate("survey-root", { onLoadedEvent: () => analytics.track("survey_loaded"), afterSubmitEvent: ({ completed }) => { if (completed) analytics.track("survey_completed"); }, });}, []);Mira Eventos de ciclo de vida para la superficie completa.