22. Loading Strategy: Skeletons vs Spinners

Loading Strategy yang tepat sangat krusial untuk meningkatkan Perceived Performance (persepsi kecepatan aplikasi oleh pengguna) dan menghindarkan layout shifting (pergeseran layout yang mengganggu).

Secara umum, kita membagi strategi loading menjadi dua: Skeleton Screens dan Spinners.


A. Perbandingan Utama: Kapan Menggunakan Apa?

Kriteria / Aspek💀 Skeleton Screens🔄 Spinners / Loaders
DefinisiVisualisasi struktur layout kosong (placeholders) yang meniru bentuk konten asli yang akan dimuat.Indikator visual animasi berputar yang menunjukkan bahwa sistem sedang sibuk memproses sesuatu.
Kapan Digunakan- Halaman dengan konten yang kaya (rich content) seperti dashboard, artikel, tabel, detail profil, list card.<br>- Waktu loading diperkirakan > 1 detik.<br>- Struktur layout akhir sudah diketahui secara pasti.- Aksi instan/singkat (seperti menekan tombol Submit, Delete, Save, Sync).<br>- Ruang/layout yang sangat terbatas (misal: di dalam tombol, badge, input field).<br>- Struktur konten akhir bersifat dinamis atau tidak terprediksi.
Persepsi PenggunaAplikasi terasa lebih cepat karena konten dimuat secara bertahap dan layout tidak melompat (perceived speed lebih tinggi).Aplikasi terasa membutuhkan waktu lebih lama jika digunakan untuk loading halaman penuh, karena pengguna merasa "menunggu" proses selesai.
InteraktivitasPengguna dapat melihat penempatan layout sebelum konten lengkap muncul, mengurangi kebingungan visual.Memblokir interaksi sementara untuk mencegah aksi ganda (duplicate actions) selama proses backend berjalan.

B. Skeleton Screens: Best Practices & Aturan Implementasi

Gunakan Skeleton Screens sebagai default state saat melakukan fetch data pada level halaman (page routing) atau komponen besar (organism/card list).

1. Aturan Desain Skeleton:

  • Kemiripan Struktur: Bentuk skeleton wajib menyerupai struktur komponen asli. Jika ada avatar bulat (rounded-full), gunakan skeleton bulat. Jika ada judul teks, gunakan skeleton persegi panjang tipis dengan sudut tumpul (rounded-md).
  • Dimensi yang Akurat: Tinggi (height) dan lebar (width) skeleton harus sedekat mungkin dengan konten aslinya untuk mencegah Layout Shift (CLS - Cumulative Layout Shift) saat data selesai dimuat.
  • Gunakan Animasi Pulse/Shimmer: Jangan biarkan skeleton statis (diam) karena bisa dianggap aplikasi mengalami freeze (macet). Berikan efek animasi perubahan opacity (animate-pulse) atau efek kilauan cahaya bergeser (shimmer effect).
  • Warna Netral: Gunakan warna abu-abu muda yang halus (misalnya, bg-slate-200 atau bg-gray-200 untuk light mode, dan bg-zinc-800 atau bg-slate-800 untuk dark mode). Hindari warna yang terlalu kontras atau mencolok.

2. Contoh Implementasi Skeleton (React + Tailwind CSS):

// CardSkeleton.tsx
export default function CardSkeleton() {
  return (
    <div className="w-full max-w-sm p-4 border border-gray-200 rounded-lg shadow-sm animate-pulse bg-white">
      {/* Thumbnail Skeleton */}
      <div className="w-full h-48 bg-gray-200 rounded-md mb-4" />
      
      {/* Title & Subtitle Skeleton */}
      <div className="space-y-3">
        <div className="h-4 bg-gray-200 rounded w-3/4" />
        <div className="h-3 bg-gray-200 rounded w-1/2" />
      </div>
      
      {/* Footer Info Skeleton */}
      <div className="flex items-center justify-between mt-6">
        <div className="flex items-center space-x-2">
          {/* Avatar Skeleton */}
          <div className="w-8 h-8 bg-gray-200 rounded-full" />
          {/* Author Name Skeleton */}
          <div className="h-3 bg-gray-200 rounded w-20" />
        </div>
        {/* Action Button Skeleton */}
        <div className="h-8 bg-gray-200 rounded w-24" />
      </div>
    </div>
  );
}

C. Spinners: Best Practices & Aturan Implementasi

Spinners (atau Circular Progress indicators) sangat tepat digunakan untuk feedback aksi yang bersifat transaksional atau asinkronus jangka pendek.

1. Aturan Penggunaan Spinner:

  • Contextual Spinner (Dalam Tombol): Saat pengguna melakukan aksi seperti "Submit Form" atau "Kirim Pesan", ubah status teks tombol menjadi spinner kecil. Wajib menonaktifkan tombol (disabled) untuk mencegah penekanan berkali-kali (double submissions).
  • Hindari Full-Screen Spinner: Jangan memblokir seluruh layar dengan spinner besar di tengah untuk loading data halaman, kecuali pada inisialisasi aplikasi yang sangat kritikal (seperti auth check saat pertama kali aplikasi dibuka).
  • Posisikan di Tengah Wadah (Centering): Jika digunakan untuk memuat data di dalam area kecil (misal: widget grafik kecil atau modal popup), posisikan spinner tepat di tengah container dengan kontras warna yang baik.

2. Contoh Implementasi Spinner di dalam Button (React + Tailwind CSS):

import React from "react";

interface SubmitButtonProps {
  isLoading: boolean;
  onClick: () => void;
  label: string;
}

export default function SubmitButton({ isLoading, onClick, label }: SubmitButtonProps) {
  return (
    <button
      onClick={onClick}
      disabled={isLoading}
      className="flex items-center justify-center gap-2 px-4 py-2 text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:bg-blue-300 disabled:cursor-not-allowed transition-colors"
    >
      {isLoading && (
        <svg
          className="w-4 h-4 animate-spin text-white"
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
        >
          <circle
            className="opacity-25"
            cx="12"
            cy="12"
            r="10"
            stroke="currentColor"
            strokeWidth="4"
          />
          <path
            className="opacity-75"
            fill="currentColor"
            d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
          />
        </svg>
      )}
      {isLoading ? "Memproses..." : label}
    </button>
  );
}

D. Rekomendasi Alur Loading State (Decision Tree)

Gunakan panduan berikut untuk memutuskan loading strategy mana yang harus diimplementasikan:

graph TD
    A[Mulai Loading State] --> B{Apakah Loading di level Halaman / Komponen Besar?}
    B -- Ya --> C{Apakah struktur layout akhir sudah diketahui?}
    C -- Ya --> D[Gunakan Skeleton Screen dengan Animasi Pulse]
    C -- Tidak --> E[Gunakan Spinner Besar di Tengah Container / Section]
    
    B -- Tidak --> F{Apakah loading dipicu oleh Aksi Pengguna (Submit/Click)?}
    F -- Ya --> G[Gunakan Inline Spinner di dalam Button + disable button]
    F -- Tidak --> H[Gunakan Micro-spinner / Progress Bar minimalis]

E. Referensi Tambahan:

© 2026 Bit Group Asia. All rights reserved.

ArchitectureSecurityGuidelines