apps/docs/content/docs/react/migration/(components)/skeleton.mdx
In v2, Skeleton wrapped children and showed/hid them based on isLoaded:
import { Skeleton } from "@heroui/react";
export default function App() {
const isLoaded = false;
return (
<Skeleton isLoaded={isLoaded}>
<div className="h-24 bg-secondary" />
</Skeleton>
);
}
In v3, Skeleton is a standalone placeholder that you control visibility of manually:
import { Skeleton } from "@heroui/react";
export default function App() {
const isLoaded = false;
return (
<>
{!isLoaded ? (
<Skeleton className="h-24 rounded-lg" />
) : (
<div className="h-24 bg-secondary" />
)}
</>
);
}
v2: Wrapped children and showed/hid them based on isLoaded
v3: Standalone placeholder - you control visibility manually
| v2 Prop | v3 Location | Notes |
|---|---|---|
isLoaded | — | Control visibility manually with conditional rendering |
disableAnimation | animationType | Use animationType="shimmer" | "pulse" | "none" (use "none" to disable) |
classNames | — | Use className prop directly |
children | — | Skeleton no longer wraps content |
animationType - Controls animation type: "shimmer" (default), "pulse", or "none"<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { useState } from "react";
const [isLoaded, setIsLoaded] = useState(false);
<Skeleton className="rounded-lg" isLoaded={isLoaded}>
<div className="h-24 rounded-lg bg-secondary" />
</Skeleton>
```
const [isLoaded, setIsLoaded] = useState(false);
{!isLoaded ? (
<Skeleton className="h-24 rounded-lg" />
) : (
<div className="h-24 rounded-lg bg-secondary" />
)}
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx <div className="flex items-center gap-3"> <Skeleton className="flex rounded-full w-12 h-12" /> <div className="w-full flex flex-col gap-2"> <Skeleton className="h-3 w-3/5 rounded-lg" /> <Skeleton className="h-3 w-4/5 rounded-lg" /> </div> </div>
</Tab>
<Tab value="v3">
tsx <div className="flex items-center gap-3"> <Skeleton className="h-12 w-12 shrink-0 rounded-lg" /> <div className="flex-1 space-y-2"> <Skeleton className="h-3 w-full rounded" /> <Skeleton className="h-3 w-4/5 rounded" /> </div> </div>
</Tab>
</Tabs>
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx <Skeleton> <div className="h-24 bg-default-300" /> </Skeleton> <Skeleton disableAnimation> <div className="h-24 bg-default-300" /> </Skeleton>
</Tab>
<Tab value="v3">
tsx <Skeleton animationType="shimmer" className="h-24 rounded-lg" /> <Skeleton animationType="pulse" className="h-24 rounded-lg" /> <Skeleton animationType="none" className="h-24 rounded-lg" />
</Tab>
</Tabs>
<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { useState } from "react";
const [isLoaded, setIsLoaded] = useState(false);
<Card className="w-[200px] space-y-5 p-4" radius="lg">
<Skeleton className="rounded-lg" isLoaded={isLoaded}>
<div className="h-24 rounded-lg bg-secondary" />
</Skeleton>
<div className="space-y-3">
<Skeleton className="w-3/5 rounded-lg" isLoaded={isLoaded}>
<div className="h-3 w-full rounded-lg bg-secondary" />
</Skeleton>
<Skeleton className="w-4/5 rounded-lg" isLoaded={isLoaded}>
<div className="h-3 w-full rounded-lg bg-secondary-300" />
</Skeleton>
</div>
</Card>
```
const [isLoaded, setIsLoaded] = useState(false);
<Card className="w-[250px] space-y-5 rounded-lg p-4">
{!isLoaded ? (
<>
<Skeleton className="h-32 rounded-lg" />
<div className="space-y-3">
<Skeleton className="h-3 w-3/5 rounded-lg" />
<Skeleton className="h-3 w-4/5 rounded-lg" />
</div>
</>
) : (
<>
<div className="h-32 rounded-lg bg-secondary" />
<div className="space-y-3">
<div className="h-3 w-3/5 rounded-lg bg-secondary" />
<div className="h-3 w-4/5 rounded-lg bg-secondary-300" />
</div>
</>
)}
</Card>
```
In v3, you can create a synchronized shimmer that passes over all skeleton elements at once. Apply the skeleton--shimmer class to a parent container and set animationType="none" on each child Skeleton:
<div className="skeleton--shimmer space-y-4 rounded-lg p-4">
<Skeleton animationType="none" className="h-32 rounded-lg" />
<div className="space-y-3">
<Skeleton animationType="none" className="h-3 w-3/5 rounded-lg" />
<Skeleton animationType="none" className="h-3 w-4/5 rounded-lg" />
</div>
</div>
This is useful for card-like layouts where you want a single, unified shimmer sweep instead of each skeleton animating independently.
In v3, you can set a default animation type globally using CSS variables:
:root {
--skeleton-animation: pulse; /* shimmer, pulse, or none */
}
This can be overridden by the animationType prop on individual components.
isLoaded Prop: Control visibility manually with conditional renderingdisableAnimation → animationType ("shimmer", "pulse", "none")classNames → className prop directlyskeleton--shimmer class on a parent container with animationType="none" on children for a unified shimmer sweep