close

DEV Community

Silviu Technology
Silviu Technology

Posted on

React: estados vacíos que sí orientan

Los estados vacíos parecen una parte menor de una app, pero afectan bastante la sensación de calidad. Cuando una tabla, una bandeja o una búsqueda no tiene resultados, ese momento le dice a la persona si la interfaz entiende su contexto o solo muestra un hueco elegante. En equipos frontend he visto que este detalle se deja para el final, y luego cuesta mucho explicar por qué una vista se siente rara aunque todo "funcione".

Además, ese primer vacío aparece muy pronto: al abrir una cuenta nueva, al limpiar filtros o al empezar un flujo interno. Incluso en herramientas de soporte, donde alguien anota cosas como temp org mail para pruebas, el problema no es solo no tener datos, sino no saber qué hacer despues.

Por qué los estados vacíos suelen confundir más de lo que ayudan

Muchos empty states fallan por tres razones:

  • describen el problema con una frase muy genérica
  • no explican la siguiente acción posible
  • cambian tanto el layout que parece otra pantalla distinta

Eso rompe continuidad. La persona venía leyendo una lista y de pronto encuentra una ilustración, un bloque centrado y un botón que quizá ni aplica. No es dramático, pero sí desgasta. Nielsen Norman Group lleva años insistiendo en que los mensajes de interfaz deben reducir incertidumbre y guiar la acción, no solo llenar espacio (https://www.nngroup.com/articles/error-message-guidelines/).

También me gusta mirar este tema desde el mismo criterio con el que intentamos aislar flujos automatizados sin perder trazabilidad: cuando el estado es ambiguo, el usuario termina adivinando. En frontend, adivinar casi siempre significa fricción.

Qué información necesita ver una persona en ese momento

Un buen estado vacío no necesita ser largo. Normalmente basta con responder cuatro preguntas:

  1. Qué está vacío.
  2. Por qué puede estar vacío.
  3. Qué acción inmediata conviene hacer.
  4. Qué pasa si no hago nada ahora.

Por ejemplo, "No hay resultados" sirve poco. En cambio, "Todavía no tienes campañas activas. Crea la primera o cambia el rango de fechas" ya orienta mucho mejor. Ese pequeño cambio reduce carga cognitiva, y se nota aunque el componente sea sencillo.

En productos con métricas o mensajería interna, también conviene distinguir entre "aún no existe contenido" y "el filtro actual no muestra contenido". Parece un matiz pequeño, pero evita tickets innecesarios. Ese mismo tipo de claridad aparece cuando alguien necesita probar upgrades por email sin ruido: una interfaz útil separa causas distintas en vez de meterlas en el mismo cajón.

Un patrón simple en React para no rehacer la pantalla entera

Mi enfoque preferido es mantener la estructura base y cambiar solo la capa de contenido. Así el usuario conserva referencias visuales y el layout no "salta" tanto. Algo así:

type EmptyStateProps = {
  title: string;
  message: string;
  actionLabel?: string;
  onAction?: () => void;
};

function EmptyState({ title, message, actionLabel, onAction }: EmptyStateProps) {
  return (
    <section className="empty-state" aria-live="polite">
      <h2>{title}</h2>
      <p>{message}</p>
      {actionLabel && onAction ? (
        <button type="button" onClick={onAction}>
          {actionLabel}
        </button>
      ) : null}
    </section>
  );
}
Enter fullscreen mode Exit fullscreen mode

Y luego, dentro de la vista principal:

if (isLoading) return <SkeletonList />;

if (items.length === 0) {
  return (
    <EmptyState
      title="No hay elementos todavía"
      message="Crea el primero o ajusta los filtros para ver resultados."
      actionLabel="Crear elemento"
      onAction={() => openCreateModal()}
    />
  );
}

return <ItemsTable items={items} />;
Enter fullscreen mode Exit fullscreen mode

Lo importante no es el componente en sí, sino el contrato. Un estado vacío debería recibir intención, no solo texto suelto. Si el mensaje depende del filtro, del permiso o del onboarding, conviene modelarlo desde datos y no resolverlo con condicionales desperdigados. Suena obvio, pero muchas vistas crecen medio sin querer y acaban dificiles de mantener.

Detalles de CSS y accesibilidad que cambian la percepción

En CSS, casi siempre prefiero evitar el centrado total de pantalla salvo que sea una pantalla inicial. Cuando el empty state vive dentro de una tabla, una lista o un panel, funciona mejor respetar contenedores, spacing y anchuras del resto de la UI.

.empty-state {
  display: grid;
  gap: 0.75rem;
  padding: 1.25rem;
  border: 1px solid var(--border-subtle);
  border-radius: 16px;
  background: linear-gradient(180deg, #fffdf8, #fffaf0);
}

.empty-state p {
  max-width: 48ch;
  color: var(--text-muted);
}
Enter fullscreen mode Exit fullscreen mode

Hay tres comprobaciones que me ayudan bastante:

  • que el título explique contexto real y no marketing
  • que el botón tenga una consecuencia clara
  • que aria-live solo se use cuando el contenido cambia tras una acción del usuario

Sobre rendimiento, no hace falta obsesionarse, pero sí conviene evitar estados vacíos enormes con ilustraciones pesadas o librerías extra. El Web Almanac muestra de forma repetida que el peso de JavaScript sigue siendo uno de los factores que más penalizan la experiencia en la web (https://almanac.httparchive.org/en/2024/javascript). A veces el estado más rapido y más claro es también el más humilde.

Q&A rápida

¿Conviene esconder filtros cuando no hay datos?

Casi nunca. Si el vacío viene de los filtros, esconderlos empeora el problema. Mejor mantenerlos visibles y dejar claro qué está limitando los resultados.

¿Hace falta una ilustración?

No siempre. Si aporta contexto, bien. Si solo ocupa espacio, sobra. En bastantes productos B2B una buena jerarquía tipográfica resuelve más que un dibujo bonito.

¿El estado vacío debe ser igual en desktop y móvil?

La intención sí, pero el layout no necesariamente. En móvil me funciona mejor reducir texto, apilar acciones y evitar bloques demasiado altos. Si no, la acción principal queda muy abajo y la pantalla se siente torpe, casi incomoda.

Checklist antes de publicar

  • El mensaje distingue entre "sin datos todavía" y "sin resultados por filtro".
  • La acción principal es específica y visible.
  • El layout conserva la estructura de la vista anterior.
  • El componente no añade peso innecesario ni dependencias raras.
  • La accesibilidad está pensada para cambios reales de estado, no por costumbre.

Cuando un estado vacío está bien resuelto, la interfaz parece más tranquila, más clara y bastante más confiable. No suele ganar aplausos en la demo, pero en uso diario se nota un monton.

Top comments (0)