π Auto-adapting shimmer loader untuk React yang otomatis menyesuaikan bentuk, ukuran, dan posisi dengan UI asli Anda. Tidak ada lagi skeleton manual yang tidak presisi!
- π― Auto-Measurement: Shimmer otomatis mengukur dimensi elemen asli (teks, gambar, button, dll)
- π§ Smart Caching: Dimensi disimpan per
cacheKey, shimmer presisi di load berikutnya - π¨ Blueprint Skeleton: Berikan template JSX di prop
skeletonuntuk first-load yang akurat - π Padding & Border Aware: Mendukung padding, border, border-radius, dan box-shadow via props
- π Resize Observer: Auto-update saat konten berubah ukuran (responsive, flex-wrap, dll)
- π Framework Agnostic: Tidak tergantung Tailwind, Bootstrap, atau CSS framework apapun
- π’ Next.js Ready: SSR-safe, bekerja sempurna di Next.js (App Router / Pages Router) dengan
"use client" - π¦ Zero CSS Import: Komponen sepenuhnya self-contained, CSS di-inject otomatis
- π οΈ TypeScript Ready: Full type definitions included
# npm
npm install @ubay182/react-auto-shimmer
# yarn
yarn add @ubay182/react-auto-shimmer
# pnpm
pnpm add @ubay182/react-auto-shimmerimport React, { useState, useEffect } from "react";
import { AutoShimmer } from "@ubay182/react-auto-shimmer";
const ProfileCard = () => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
useEffect(() => {
// Simulasi fetch data
setTimeout(() => {
setData({ title: "Hello World", description: "This is a description." });
setLoading(false);
}, 2000);
}, []);
return (
<AutoShimmer
loading={loading}
cacheKey="my-card"
skeleton={
<div className="card">
<h2>Loading title...</h2>
<p>Loading description...</p>
</div>
}
>
{/* Konten Asli */}
<div className="card">
<h2>{data?.title}</h2>
<p>{data?.description}</p>
</div>
</AutoShimmer>
);
};
export default ProfileCard;Pastikan menambahkan "use client" di paling atas file komponen Anda karena AutoShimmer memerlukan akses ke DOM (seperti ResizeObserver dan getBoundingClientRect).
"use client";
import React, { useState, useEffect } from "react";
import { AutoShimmer } from "@ubay182/react-auto-shimmer";
import Link from "next/link";
export default function UserProfile() {
const [loading, setLoading] = useState(true);
const [user, setUser] = useState<any>(null);
const fetchData = () => {
setLoading(true);
const names = ["Ubaidillah Rahman", "Budi Santoso", "Siti Aminah"];
const randomName = names[Math.floor(Math.random() * names.length)];
setTimeout(() => {
setUser({
name: randomName,
bio: "Fullstack Developer & React Enthusiast.",
avatar: "https://placehold.co/100x100/e2e8f0/475569?text=UR",
tags: ["React", "TypeScript", "UI/UX", "Next.js", "Tailwind"],
});
setLoading(false);
}, 3000);
};
useEffect(() => {
fetchData();
}, []);
return (
<AutoShimmer
loading={loading}
cacheKey="user-profile-nextjs"
border="1px solid #e5e7eb"
borderRadius="12px"
boxShadow="0 4px 12px rgba(0,0,0,0.05)"
bgColor="#ffffff"
padding="1.5rem"
skeleton={
<div className="flex flex-col items-center text-center w-full">
<div className="w-16 h-16 rounded-full bg-gray-200 mb-4"></div>
<h2 className="w-3/5 h-6 bg-gray-200 rounded mb-2"></h2>
<p className="w-full h-4 bg-gray-200 rounded mb-4"></p>
<div className="flex flex-wrap gap-2 mb-4 justify-center w-full">
{[...Array(5)].map((_, i) => (
<span
key={i}
className="inline-block w-16 h-6 bg-gray-200 rounded-full"
></span>
))}
</div>
<button className="px-5 py-2.5 border-none rounded-lg font-medium text-sm bg-indigo-600 text-white mt-2">
View Profile
</button>
</div>
}
>
{/* KONTEN ASLI */}
<div className="flex flex-col items-center text-center w-full">
{user?.avatar && (
<img
src={user.avatar}
alt={user.name}
className="w-16 h-16 rounded-full mb-4 object-cover"
/>
)}
<h2 className="text-2xl font-bold text-gray-900 mb-2 w-full">
{user?.name || "Loading Name..."}
</h2>
<p className="text-gray-600 leading-relaxed mb-4 w-full">
{user?.bio || "Loading bio..."}
</p>
<div className="flex flex-wrap gap-2 mb-4 justify-center w-full">
{user?.tags?.map((tag: string) => (
<span
key={tag}
className="bg-indigo-50 text-indigo-800 px-3 py-1 rounded-full text-sm font-medium whitespace-nowrap"
>
{tag}
</span>
))}
</div>
<button className="px-5 py-2.5 border-none rounded-lg cursor-pointer font-medium text-sm bg-indigo-600 text-white mt-2">
<Link href="/profile" className="text-white decoration-none">
View Profile
</Link>
</button>
</div>
</AutoShimmer>
);
}| Prop | Tipe | Default | Deskripsi |
|---|---|---|---|
| loading | boolean | false |
Kontrol state loading (true = tampilkan shimmer) |
| cacheKey | string | - | Unique key untuk caching dimensi. Wajib agar shimmer presisi di refresh berikutnya |
| border | string | '1px solid #e5e7eb' |
CSS border untuk wrapper container |
| borderRadius | string | '8px' |
CSS border-radius untuk wrapper |
| boxShadow | string | '0 2px 8px rgba(0,0,0,0.05)' |
CSS box-shadow untuk wrapper |
| bgColor | string | '#ffffff' |
Background color wrapper |
| padding | string | '1.5rem' |
Padding internal wrapper (shimmer blocks diukur relatif terhadap area ini) |
| skeleton | ReactNode | - | Blueprint JSX untuk first-load shimmer. Strukturnya sebaiknya mirip konten asli |
| children | ReactNode | - | Konten asli yang akan ditampilkan saat loading=false dan diukur posisinya |
Gunakan atribut data-shimmer-ignore untuk mengecualikan elemen tertentu agar tidak diubah menjadi shimmer block:
<div>
<h2>Title</h2>
<p data-shimmer-ignore>Ini tidak akan ditimpa shimmer block</p>
<button>Action</button>
</div>Gunakan data-shimmer-skip jika ada section besar yang ingin diabaikan sepenuhnya oleh scanner ukuran:
<div data-shimmer-skip>
{/* Konten ini tidak akan di-scan untuk shimmer */}
<StaticBanner />
</div># Clone repo
git clone https://github.com/ubay1/react-auto-shimmer.git
cd react-auto-shimmer
# Install dependencies
npm install
# Run playground (dev mode)
npm run dev
# Build library
npm run buildContributions welcome!
Silakan:
- Fork repo
- Buat branch fitur (
git checkout -b feat/amazing-feature) - Commit perubahan (
git commit -m 'Add amazing feature') - Push ke branch (
git push origin feat/amazing-feature) - Buka Pull Request
Pastikan:
- β Code mengikuti style yang ada
- β Tidak ada error TypeScript
- β Playground masih berjalan normal
- β Update README jika menambah fitur baru
MIT License - see LICENSE file for details.
