@mshafiqyajid/react-skeleton
Headless skeleton hook and styled loading placeholder. Four variants (rect/line/circle/text), pulse and wave animations, configurable radius, custom base and highlight colors, repeat count with spacing, inline layout, fit-content sizing, and reduced-motion support. Zero dependencies.
Playground #
import { SkeletonStyled } from "@mshafiqyajid/react-skeleton/styled";
import "@mshafiqyajid/react-skeleton/styles.css";
<SkeletonStyled />Install #
npm install @mshafiqyajid/react-skeleton Quick start #
import { SkeletonStyled } from "@mshafiqyajid/react-skeleton/styled";
import "@mshafiqyajid/react-skeleton/styles.css";
// Rectangle placeholder
<SkeletonStyled width="100%" height={20} />
// Circle avatar
<SkeletonStyled variant="circle" width="2.5rem" height="2.5rem" />
// Text block (3 lines, last at 60%)
<SkeletonStyled variant="text" lines={3} lastLineWidth="60%" />
// Wave shimmer
<SkeletonStyled animation="wave" width="100%" height={80} /> Card skeleton composition #
import { SkeletonStyled } from "@mshafiqyajid/react-skeleton/styled";
import "@mshafiqyajid/react-skeleton/styles.css";
function CardSkeleton() {
return (
<div style={{ display: "flex", gap: "1rem", alignItems: "flex-start" }}>
<SkeletonStyled variant="circle" width="2.5rem" height="2.5rem" />
<div style={{ flex: 1, display: "flex", flexDirection: "column", gap: "0.5rem" }}>
<SkeletonStyled variant="line" height="0.875rem" width="60%" />
<SkeletonStyled variant="line" height="0.75rem" width="40%" />
<SkeletonStyled variant="text" lines={3} />
</div>
</div>
);
} Headless #
import { useSkeleton } from "@mshafiqyajid/react-skeleton";
function MySkeleton() {
const { skeletonProps } = useSkeleton();
return (
<div {...skeletonProps} className="my-skeleton">
{/* your placeholder shape */}
</div>
);
} Repeated skeletons #
// Stack 4 line skeletons with 12px gap
<SkeletonStyled variant="line" count={4} spacing={12} />
// Inline badges
<SkeletonStyled variant="rect" count={3} inline spacing={8} width={64} height={24} radius="full" />
// Disable animation for all items in the group
<SkeletonStyled count={3} enableAnimation={false} /> Custom colors #
Override the base skeleton color and the wave shimmer highlight with baseColor and highlightColor. Both accept any valid CSS color string and set the underlying CSS variables (--rsk-bg and --rsk-wave-highlight) inline so overrides are scoped to that specific element.
{/* Blue-tinted skeleton β useful for matching a card's background */}
<SkeletonStyled
animation="wave"
width="100%"
height={80}
baseColor="#bfdbfe"
highlightColor="#dbeafe"
/>
{/* Warm tone */}
<SkeletonStyled
animation="wave"
variant="text"
lines={3}
baseColor="#fde68a"
highlightColor="#fef3c7"
/> Custom border radius #
The radius prop covers the preset scale ("none" β "full"). For anything in between, pass borderRadius with any CSS value β it overrides the preset via --rsk-custom-radius.
{/* Pill badge skeleton */}
<SkeletonStyled width={80} height={24} borderRadius="20px" />
{/* Slightly rounded card */}
<SkeletonStyled variant="rect" width="100%" height={120} borderRadius={6} /> fitContent #
By default the skeleton expands to fill available space. Set fitContent to size the element to its natural content dimensions instead β useful when wrapping a skeleton around a specific element shape inside a flex container.
<div style={{ display: "flex", gap: "0.5rem" }}>
<SkeletonStyled variant="rect" fitContent width={48} height={48} />
<SkeletonStyled variant="text" fitContent lines={2} />
</div> CSS variables #
:root {
--rsk-bg: #e4e4e7;
--rsk-wave-highlight: rgba(255, 255, 255, 0.7);
--rsk-radius-sm: 4px;
--rsk-radius-md: 8px;
--rsk-radius-lg: 12px;
--rsk-duration-pulse: 1.4s;
--rsk-duration-wave: 1.6s;
} API #
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "rect" | "line" | "circle" | "text" | "rect" | Shape variant |
| animation | "pulse" | "wave" | "none" | "pulse" | Animation style |
| width | string | number | β | Width (e.g. "100%", 200, "12rem") |
| height | string | number | β | Height (e.g. 20, "1rem") |
| radius | "none" | "sm" | "md" | "lg" | "full" | "sm" | Border radius preset |
| borderRadius | string | number | β | Custom border-radius, overrides radius preset |
| lines | number | 3 | Number of lines (text variant only) |
| lastLineWidth | string | "60%" | Width of last line (text variant only) |
| count | number | 1 | Render N skeletons stacked; wraps in .rsk-group |
| spacing | number | 8 | Gap in px between items when count > 1 |
| inline | boolean | false | Use inline-block display; group becomes inline-flex |
| baseColor | string | β | Override skeleton base color (sets --rsk-bg) |
| highlightColor | string | β | Override shimmer highlight color (sets --rsk-wave-highlight) |
| enableAnimation | boolean | true | Set to false to disable animation (same as animation="none") |
| fitContent | boolean | false | Size skeleton to its natural content dimensions |
| className | string | β | Extra class on root |
| style | CSSProperties | β | Inline style override |