GALERÍA DE COMPONENTES

Cargas y animaciones

Haz visible la espera en cada parte de tu interfaz.

Elige cómo se ve la espera

Lottie + Font Awesome

Prueba la órbita de KC con Lottie, la sincronización con Font Awesome o los indicadores esenciales. Selecciona la duración de las demostraciones. Todos los ejemplos respetan el modo oscuro, el acento y la preferencia de movimiento reducido.

Son simulaciones locales. En tu proyecto, muestra la carga al iniciar la operación y ciérrala en finally al terminar.

Ver y copiar HTML
<section id="loading-options" class="panel demo-card" data-component="loading-options">
  <div class="panel-heading">
    <h2>Elige cómo se ve la espera</h2>
    <span class="tag">Lottie + Font Awesome</span>
  </div>
  <p class="demo-description">
    Prueba la órbita de KC con Lottie, la sincronización con Font Awesome o los indicadores
    esenciales. Selecciona la duración de las demostraciones. Todos los ejemplos respetan el modo
    oscuro, el acento y la preferencia de movimiento reducido.
  </p>
  <div class="demo-grid two">
    <label class="demo-label-block"
      >Animación<select id="loading-style" class="demo-input">
        <option value="lottie">Órbita KC · Lottie</option>
        <option value="icon">Sincronización · Font Awesome</option>
        <option value="ring">Anillo giratorio</option>
        <option value="dots">Puntos saltando</option>
        <option value="bars">Barras animadas</option>
      </select></label
    >
    <label class="demo-label-block"
      >Duración de ejemplo<select id="loading-duration" class="demo-input">
        <option value="2000">2 segundos</option>
        <option value="4000" selected>4 segundos</option>
        <option value="8000">8 segundos</option>
      </select></label
    >
  </div>
  <p class="demo-inline-output">
    Son simulaciones locales. En tu proyecto, muestra la carga al iniciar la operación y ciérrala en
    finally al terminar.
  </p>
</section>

Carga dentro de un div

Lottie + Font Awesome

Bloquea solamente esta card: el resto de la pantalla sigue disponible.

RESUMEN DEL MES

Tu próximo objetivo está cerca.

Este contenido permanece debajo de la capa de carga.

La card está lista.
Ver y copiar HTML
<section id="loading-block" class="panel demo-card" data-component="loading-block">
  <div class="panel-heading">
    <h2>Carga dentro de un div</h2>
    <span class="tag">Lottie + Font Awesome</span>
  </div>
  <p class="demo-description">
    Bloquea solamente esta card: el resto de la pantalla sigue disponible.
  </p>
  <button class="btn lime" type="button" id="start-block-loading">Cargar card</button>
  <div class="loading-region" id="loading-region" aria-busy="false">
    <div id="loading-region-content">
      <p class="eyebrow">RESUMEN DEL MES</p>
      <h3>Tu próximo objetivo está cerca.</h3>
      <p class="muted">Este contenido permanece debajo de la capa de carga.</p>
    </div>
    <div class="loading-cover" id="block-loading" hidden>
      <div class="loading-message">
        <span class="loading-kicker"
          ><i class="fa-solid fa-layer-group" aria-hidden="true"></i> KC WORKSPACE</span
        >
        <span class="loading-symbol" aria-hidden="true"
          ><span
            class="loading-lottie kc-motion"
            data-lottie-src="../assets/animations/kc-orbit.json"
            aria-hidden="true"
            ><span data-motion-canvas></span
            ><i
              class="fa-solid fa-circle-notch fa-spin motion-fallback"
              aria-hidden="true"
            ></i></span
          ><span class="loading-fontawesome"
            ><i class="fa-solid fa-arrows-rotate fa-spin" aria-hidden="true"></i
            ><span class="loading-icon-dot"></span
          ></span>
          <span class="loading-ring"></span>
          <span class="loading-dots"><span></span><span></span><span></span></span>
          <span class="loading-bars"
            ><span></span><span></span><span></span><span></span
          ></span> </span
        ><strong>Cargando...</strong><span>Actualizando el resumen</span
        ><span class="loading-track" aria-hidden="true"></span
        ><button class="btn outline" type="button" id="cancel-block-loading">Cancelar</button>
      </div>
    </div>
  </div>
  <output id="block-loading-status" class="demo-inline-output" role="status"
    >La card está lista.</output
  >
</section>

Carga en un modal

Lottie + Font Awesome

Abre un diálogo centrado con fondo atenuado. Puedes cancelar con el botón o con Escape.

KC WORKSPACE

Cargando...

Estamos preparando tu reporte de ejemplo.

El modal está listo.
Ver y copiar HTML
<section id="loading-modal-demo" class="panel demo-card" data-component="loading-modal">
  <div class="panel-heading">
    <h2>Carga en un modal</h2>
    <span class="tag">Lottie + Font Awesome</span>
  </div>
  <p class="demo-description">
    Abre un diálogo centrado con fondo atenuado. Puedes cancelar con el botón o con Escape.
  </p>
  <button class="btn lime" type="button" id="start-modal-loading">Abrir modal de carga</button>
  <dialog
    id="loading-modal"
    class="loading-dialog"
    aria-labelledby="loading-modal-title"
    aria-describedby="loading-modal-description"
  >
    <div class="loading-message" aria-busy="true">
      <span class="loading-kicker"
        ><i class="fa-solid fa-layer-group" aria-hidden="true"></i> KC WORKSPACE</span
      >
      <span class="loading-symbol" aria-hidden="true"
        ><span
          class="loading-lottie kc-motion"
          data-lottie-src="../assets/animations/kc-orbit.json"
          aria-hidden="true"
          ><span data-motion-canvas></span
          ><i class="fa-solid fa-circle-notch fa-spin motion-fallback" aria-hidden="true"></i></span
        ><span class="loading-fontawesome"
          ><i class="fa-solid fa-arrows-rotate fa-spin" aria-hidden="true"></i
          ><span class="loading-icon-dot"></span
        ></span>
        <span class="loading-ring"></span>
        <span class="loading-dots"><span></span><span></span><span></span></span>
        <span class="loading-bars"><span></span><span></span><span></span><span></span></span>
      </span>
      <h2 id="loading-modal-title">Cargando...</h2>
      <p id="loading-modal-description">Estamos preparando tu reporte de ejemplo.</p>
      <span class="loading-track" aria-hidden="true"></span
      ><button class="btn outline" type="button" id="cancel-modal-loading" autofocus>
        Cancelar
      </button>
    </div>
  </dialog>
  <output id="modal-loading-status" class="demo-inline-output" role="status"
    >El modal está listo.</output
  >
</section>

Carga sobre toda la pantalla

Lottie + Font Awesome

Cubre el body completo, incluidos el menú y la barra superior. El navegador mantiene el foco dentro de la capa hasta cerrarla.

KC WORKSPACE

Cargando...

Sincronizando tu espacio de trabajo de ejemplo.

La pantalla está lista.
Ver y copiar HTML
<section id="loading-body" class="panel demo-card" data-component="loading-body">
  <div class="panel-heading">
    <h2>Carga sobre toda la pantalla</h2>
    <span class="tag">Lottie + Font Awesome</span>
  </div>
  <p class="demo-description">
    Cubre el body completo, incluidos el menú y la barra superior. El navegador mantiene el foco
    dentro de la capa hasta cerrarla.
  </p>
  <button class="btn lime" type="button" id="start-body-loading">Cargar pantalla completa</button>
  <dialog
    id="loading-body-dialog"
    class="loading-dialog loading-fullscreen"
    aria-labelledby="loading-body-title"
    aria-describedby="loading-body-description"
  >
    <div class="loading-message" aria-busy="true">
      <span class="loading-kicker"
        ><i class="fa-solid fa-layer-group" aria-hidden="true"></i> KC WORKSPACE</span
      >
      <span class="loading-symbol" aria-hidden="true"
        ><span
          class="loading-lottie kc-motion"
          data-lottie-src="../assets/animations/kc-orbit.json"
          aria-hidden="true"
          ><span data-motion-canvas></span
          ><i class="fa-solid fa-circle-notch fa-spin motion-fallback" aria-hidden="true"></i></span
        ><span class="loading-fontawesome"
          ><i class="fa-solid fa-arrows-rotate fa-spin" aria-hidden="true"></i
          ><span class="loading-icon-dot"></span
        ></span>
        <span class="loading-ring"></span>
        <span class="loading-dots"><span></span><span></span><span></span></span>
        <span class="loading-bars"><span></span><span></span><span></span><span></span></span>
      </span>
      <h2 id="loading-body-title">Cargando...</h2>
      <p id="loading-body-description">Sincronizando tu espacio de trabajo de ejemplo.</p>
      <span class="loading-track" aria-hidden="true"></span
      ><button class="btn outline" type="button" id="cancel-body-loading" autofocus>
        Cancelar carga
      </button>
    </div>
  </dialog>
  <output id="body-loading-status" class="demo-inline-output" role="status"
    >La pantalla está lista.</output
  >
</section>

Carga en un botón

Sin biblioteca

Una operación pequeña puede mostrar su estado directamente en el botón y evitar clics repetidos.

Listo para guardar.
Ver y copiar HTML
<section id="loading-button" class="panel demo-card" data-component="loading-button">
  <div class="panel-heading">
    <h2>Carga en un botón</h2>
    <span class="tag">Sin biblioteca</span>
  </div>
  <p class="demo-description">
    Una operación pequeña puede mostrar su estado directamente en el botón y evitar clics repetidos.
  </p>
  <button class="btn lime loading-action" type="button" id="start-button-loading" aria-busy="false">
    <span id="button-loading-icon" hidden
      ><span class="loading-symbol" aria-hidden="true"
        ><span
          class="loading-lottie kc-motion"
          data-lottie-src="../assets/animations/kc-orbit.json"
          aria-hidden="true"
          ><span data-motion-canvas></span
          ><i class="fa-solid fa-circle-notch fa-spin motion-fallback" aria-hidden="true"></i></span
        ><span class="loading-fontawesome"
          ><i class="fa-solid fa-arrows-rotate fa-spin" aria-hidden="true"></i
          ><span class="loading-icon-dot"></span
        ></span>
        <span class="loading-ring"></span>
        <span class="loading-dots"><span></span><span></span><span></span></span>
        <span class="loading-bars"
          ><span></span><span></span><span></span><span></span
        ></span> </span></span
    ><span id="button-loading-label">Guardar ejemplo</span>
  </button>
  <output id="button-loading-status" class="demo-inline-output" role="status"
    >Listo para guardar.</output
  >
</section>

Skeleton de contenido

Sin biblioteca

Anticipa la estructura de la card con una animación suave mientras llegan los datos.

TU PERFIL

Andrea Flores

Tu información de ejemplo está disponible.

Perfil listo.
Ver y copiar HTML
<section id="loading-skeleton" class="panel demo-card" data-component="loading-skeleton">
  <div class="panel-heading">
    <h2>Skeleton de contenido</h2>
    <span class="tag">Sin biblioteca</span>
  </div>
  <p class="demo-description">
    Anticipa la estructura de la card con una animación suave mientras llegan los datos.
  </p>
  <button class="btn lime" type="button" id="start-skeleton-loading">Probar skeleton</button>
  <div class="loading-region" id="skeleton-region" aria-busy="false">
    <div id="skeleton-placeholder" class="loading-skeleton" hidden aria-hidden="true">
      <span class="skeleton-avatar"></span><span class="skeleton-line"></span
      ><span class="skeleton-line short"></span><span class="skeleton-line"></span>
    </div>
    <div id="skeleton-content">
      <p class="eyebrow">TU PERFIL</p>
      <h3>Andrea Flores</h3>
      <p class="muted">Tu información de ejemplo está disponible.</p>
    </div>
  </div>
  <output id="skeleton-loading-status" class="demo-inline-output" role="status"
    >Perfil listo.</output
  >
</section>

Cómo usar las cargas en JavaScript

Código reutilizable

Copia los bloques HTML que necesites, loading.css y loading.js. El script reconoce los bloques presentes; puedes conservar solo el que necesites. Los selectores son opcionales: sin ellos se usa la órbita KC y una simulación de 4 segundos. Los tiempos son solo una simulación. Para datos reales, abre la carga antes de tu petición y llama a la función de cierre en finally; conserva también Font Awesome, lottie_light.min.js y motion.js para los indicadores avanzados.

Archivo de configuración: assets/js/loading.js. El HTML permanece en su archivo; aquí solo se configuran datos, eventos e interacciones.

Ver archivos necesarios y orden de carga
<script src="../assets/js/theme.js"></script>
<link rel="stylesheet" href="../assets/css/tailwind.css" />
<link rel="stylesheet" href="../assets/css/styles.css" />
<link rel="stylesheet" href="../assets/css/video.css" />
<link rel="stylesheet" href="../assets/css/appearance.css" />
<script defer="" src="../assets/js/shared.js"></script>
<script defer="" src="../assets/js/ui.js"></script>
<script defer="" src="../assets/js/appearance.js"></script>
<script defer="" src="../assets/js/components.js"></script>
<link rel="stylesheet" href="../assets/css/components.css" />
<link rel="stylesheet" href="../assets/css/loading.css" />
<script defer src="../assets/js/loading.js"></script>
<link rel="stylesheet" href="../assets/vendor/fontawesome/css/all.min.css" />
<link rel="stylesheet" href="../assets/css/media-components.css" />
<script defer src="../assets/vendor/lottie-web/lottie_light.min.js"></script>
<script defer src="../assets/js/motion.js"></script>
Ver y copiar JavaScript
// Loading behavior only. Indicators, dialogs and skeleton markup live in ui-cargas.html.
// Reuse: const stop = KCLoading.start("block"); try { await operation(); } finally { stop(); }
(() => {
  const active = new Map();
  const definitions = {
    block: {
      button: "start-block-loading",
      busy: "loading-region",
      layer: "block-loading",
      content: "loading-region-content",
      status: "block-loading-status",
      cancel: "cancel-block-loading",
    },
    modal: {
      button: "start-modal-loading",
      dialog: "loading-modal",
      status: "modal-loading-status",
      cancel: "cancel-modal-loading",
    },
    body: {
      button: "start-body-loading",
      dialog: "loading-body-dialog",
      status: "body-loading-status",
      cancel: "cancel-body-loading",
    },
    button: {
      button: "start-button-loading",
      busy: "start-button-loading",
      layer: "button-loading-icon",
      status: "button-loading-status",
    },
    skeleton: {
      button: "start-skeleton-loading",
      busy: "skeleton-region",
      layer: "skeleton-placeholder",
      content: "skeleton-content",
      status: "skeleton-loading-status",
    },
  };
  const byId = (id) => (id ? document.getElementById(id) : null);
  function start(kind, { duration } = {}) {
    const definition = definitions[kind];
    if (!definition) throw new Error("Tipo de carga desconocido: " + kind);
    if (active.has(kind)) return active.get(kind);
    const button = byId(definition.button);
    if (!button) throw new Error("No se encontró el HTML para la carga: " + kind);
    const dialog = byId(definition.dialog);
    const layer = byId(definition.layer);
    const busy = byId(definition.busy);
    const content = byId(definition.content);
    const status = byId(definition.status);
    const cancel = byId(definition.cancel);
    const previousFocus = document.activeElement;
    let timer;
    let finished = false;
    function syncScroll() {
      document.body.classList.toggle(
        "loading-scroll-lock",
        active.has("modal") || active.has("body"),
      );
    }
    function stop(reason = "complete") {
      if (finished) return;
      finished = true;
      clearTimeout(timer);
      active.delete(kind);
      cancel?.removeEventListener("click", onCancel);
      dialog?.removeEventListener("cancel", onEscape);
      dialog?.removeEventListener("close", onClose);
      if (dialog?.open) dialog.close();
      if (layer) layer.hidden = true;
      busy?.setAttribute("aria-busy", "false");
      if (content) {
        content.inert = false;
        content.hidden = false;
      }
      button.disabled = false;
      if (kind === "button") byId("button-loading-label").textContent = "Guardar ejemplo";
      status.textContent =
        reason === "cancel"
          ? "Carga cancelada. Puedes volver a intentarlo."
          : "Carga completada. El contenido está listo.";
      syncScroll();
      // Restore focus only when closing a blocking layer, without stealing it from other actions.
      if (
        (dialog || kind === "block") &&
        (document.activeElement === document.body ||
          dialog?.contains(document.activeElement) ||
          layer?.contains(document.activeElement))
      ) {
        previousFocus?.focus({ preventScroll: true });
      }
    }
    function onCancel() {
      stop("cancel");
    }
    function onEscape(event) {
      event.preventDefault();
      stop("cancel");
    }
    function onClose() {
      stop("cancel");
    }
    active.set(kind, stop);
    button.disabled = true;
    busy?.setAttribute("aria-busy", "true");
    if (layer) layer.hidden = false;
    if (content) {
      content.inert = true;
      content.hidden = kind === "skeleton";
    }
    status.textContent = "Cargando...";
    if (kind === "button") byId("button-loading-label").textContent = "Cargando...";
    cancel?.addEventListener("click", onCancel);
    dialog?.addEventListener("cancel", onEscape);
    dialog?.addEventListener("close", onClose);
    syncScroll();
    try {
      dialog?.showModal();
    } catch (error) {
      stop("cancel");
      throw error;
    }
    if (kind === "block") cancel.focus({ preventScroll: true });
    // No timer by default: real operations close the loading state from their finally block.
    if (Number.isFinite(duration) && duration > 0) timer = setTimeout(stop, duration);
    return stop;
  }
  window.KCLoading = Object.freeze({ start });
  const style = byId("loading-style");
  document.body.dataset.loadingStyle = style?.value || "lottie";
  style?.addEventListener("change", (event) => {
    document.body.dataset.loadingStyle = event.target.value;
  });
  Object.entries(definitions).forEach(([kind, definition]) => {
    byId(definition.button)?.addEventListener("click", () => {
      start(kind, { duration: Number(byId("loading-duration")?.value || 4000) });
    });
  });
  window.addEventListener("pagehide", () => [...active.values()].forEach((stop) => stop("cancel")));
})();

Conectar una operación real

Este ejemplo es una guía: la ruta /api/resumen no existe en la plantilla. Cancelar el indicador no cancela una petición.

Ver y copiar JavaScript con try / finally
// Después de cargar loading.js y de mantener el HTML del ejemplo:
async function actualizarResumen() {
  const cerrarCarga = KCLoading.start("block"); // "modal", "body", "button" o "skeleton"
  const estado = document.querySelector("#block-loading-status");
  let mensaje;
  try {
    // Sustituye esta ruta por tu API y actualiza los elementos HTML existentes.
    const respuesta = await fetch("/api/resumen");
    if (!respuesta.ok) throw new Error("No se pudo cargar el resumen.");
    const resumen = await respuesta.json();
    document.querySelector("#loading-region-content h3").textContent = resumen.titulo;
    mensaje = "Resumen actualizado.";
  } catch (error) {
    mensaje = error.message || "No se pudo completar la operación.";
  } finally {
    cerrarCarga();
    estado.textContent = mensaje;
  }
}
// En una integración real, conecta tu botón a actualizarResumen y elimina
// el listener de simulación de ese botón en loading.js.
// Cancelar esta demo cierra el indicador; para detener fetch usa AbortController.
© 2026 KC Finance Plantilla creada por Codar · Hecha para crecer contigo.● Todos los sistemas operativos

HAZLO TUYO

Apariencia

Tu espacio, a tu manera.

Modo de visualización
Tamaño de la interfaz

Amplía textos, botones y tarjetas. Se conserva entre pantallas.

Color de la plantilla

El acento se aplica al menú, botones y gráficas.

Fondo

Elige una base que acompañe tu color.

Se guarda en este navegador y en todas las pantallas.