Un widget de testimonios sencillo para Next.js (sin paquete npm, un solo iframe)
Estás construyendo tu portfolio o la web de un cliente en Next.js y quieres reseñas reales en ella. Podrías montar una tabla de testimonios, una pantalla de administración y un flujo de moderación, o podrías poner un solo iframe. Esta guía muestra la segunda opción con SimplerFeedback: el fragmento HTML tal cual, un pequeño componente App Router, la variante en banda para una página de inicio y lo que, siendo honestos, un iframe no puede hacer.
La idea: tus reseñas viven en un muro tuyo y tu web solo lo enmarca
Con SimplerFeedback, las reseñas se recogen con tus formularios y se publican en tu muro, una página pública en simplerfeedback.com/wall/your-slug. Esa página es la fuente de verdad: apruebas una reseña, aparece en el muro, y todas las webs que insertan el muro la muestran también.
Tu web en Next.js no guarda nada. Enmarca el muro en un iframe. El muro es HTML estático servido desde una CDN, así que no hay clave de API que proteger, ni paquete npm que instalar, ni build que volver a lanzar cuando llega una reseña nueva. Publicas una reseña en la app y lo insertado ya está al día.
El fragmento HTML tal cual
En la app, abre Mi muro, luego Compartir, y copia el código para insertar. Son dos líneas: el iframe y un script opcional que lo dimensiona.
<iframe
src="https://simplerfeedback.com/wall/your-slug?embed=wall"
title="Your name"
style="width:100%;height:900px;border:0"
loading="lazy"
></iframe>
<script src="https://simplerfeedback.com/embed.js" async></script>La altura de 900px es solo un valor de respaldo. embed.js escucha un mensaje que envía el muro con la altura real de su contenido (sf-embed-height) y ajusta la altura del iframe para que coincida, así el muro nunca muestra una barra de desplazamiento interna ni un hueco en blanco. Sin el script, el iframe simplemente mantiene la altura de su atributo style. Una sola etiqueta script basta para todos los iframes de muro de la página.
Un componente para Next.js App Router
Pegar HTML tal cual en JSX funciona, pero un pequeño componente guarda el slug en una sola prop y carga el script una vez. next/script con strategy="lazyOnload" carga embed.js cuando el navegador está libre y evita duplicarlo, así que renderizar el componente dos veces en una página no añade el script dos veces (y el script también se protege solo).
// components/TestimonialWall.tsx
'use client';
import Script from 'next/script';
type Props = {
slug: string;
title: string;
variant?: 'wall' | 'strip';
featured?: boolean; // strip only, Premium
};
export function TestimonialWall({ slug, title, variant = 'wall', featured = false }: Props) {
const params = new URLSearchParams({ embed: variant });
if (variant === 'strip' && featured) params.set('featured', '1');
const src = `https://simplerfeedback.com/wall/${encodeURIComponent(slug)}?${params}`;
return (
<>
<iframe
src={src}
title={title}
loading="lazy"
style={{ width: '100%', height: variant === 'strip' ? 320 : 900, border: 0 }}
/>
<Script src="https://simplerfeedback.com/embed.js" strategy="lazyOnload" />
</>
);
}Hay dos atributos importantes. title da al iframe un nombre accesible, que anuncian los lectores de pantalla; pon algo con sentido como “Reseñas de clientes”, no “iframe”. loading="lazy" hace que un muro situado por debajo del primer pantallazo solo se cargue cuando el visitante se acerca a él, así que no cuesta nada en la primera carga.
La banda para una página de inicio, y solo las reseñas fijadas
Un muro completo es ideal para una página /testimonials. En una página de inicio normalmente quieres una franja corta de pruebas bajo el hero. Usa ?embed=strip: una banda horizontal de reseñas, de 320px de alto por defecto. Con Premium, añade featured=1 a la banda para mostrar solo las reseñas que has fijado (hasta tres), así tu página de inicio siempre abre con las mejores.
// app/page.tsx — a strip of pinned reviews under the hero
import { TestimonialWall } from '@/components/TestimonialWall';
export default function Home() {
return (
<main>
{/* ...hero... */}
<TestimonialWall slug="your-slug" title="What clients say" variant="strip" featured />
</main>
);
}
// app/testimonials/page.tsx — the full wall
// <TestimonialWall slug="your-slug" title="Client reviews" />Estilo y maquetación
Trata el iframe como una imagen: ocupa todo el ancho de su contenedor y embed.js se encarga de la altura. Ponlo dentro del contenedor que use tu maquetación (un contenedor con ancho máximo, una celda de grid) y se adapta.
- Ancho: 100% del padre. Limita el padre, no el iframe.
- Alto: lo fija embed.js según el contenido; la altura inline es solo el respaldo.
- Los colores y el modo oscuro o claro vienen del estilo del muro, no de tu web. Tu CSS no puede entrar en un iframe de otro origen, y no deberías intentarlo.
- Elige un estilo de muro que encaje con la página (Terminal le va bien a un portfolio de desarrollador), o usa Crea el tuyo en Premium para ajustar el fondo, el color de acento y el del texto a tu marca.
Los límites, con honestidad
Es un iframe, con todo lo que eso implica. Las reseñas no se renderizan en el servidor dentro de tu DOM, así que los buscadores no atribuyen el texto de las reseñas a tu página; ese texto se indexa en la URL del muro, a la que también puedes enlazar directamente. No hay paquete de componentes React ni API pública para obtener las reseñas en JSON: el componente de arriba es tuyo para copiarlo, y el iframe es la integración.
Para la mayoría de los portfolios y webs de clientes es el equilibrio adecuado: dos minutos para añadirlo, nada que mantener y reseñas que se mantienen al día solas.