"use client";
import { Button, Skeleton, Stack, Text } from "@vortexlabs/vortex";
import { useState } from "react";
export const LoadingContent = () => {
const [loading, setLoading] = useState(true);
return (
<Stack gap={4} width="100%">
<Skeleton loading={loading} ariaLabel="Loading project details">
<Stack gap={2}>
<Text weight="medium">Design system</Text>
<Text>Components, patterns, and shared foundations.</Text>
</Stack>
</Skeleton>
<Button variant="secondary" onClick={() => setLoading(!loading)}>
{loading ? "Show loaded content" : "Show loading state"}
</Button>
</Stack>
);
};Features
- Wraps loaded content and draws shapes that match its layout.
- Builds a skeleton from sample content before data arrives.
- Draws plain blocks at a set size.
- Remembers loaded layouts with
cacheKey. - Supports pulse, shimmer, and staggered animations.
Placeholder Content
Pass fixture to measure sample content when the real content isn't available yet, like in a Suspense fallback. It replaces children for measuring.
<Skeleton
ariaLabel="Loading project card"
fixture={
<Stack gap={2}>
<Text weight="medium">Project name</Text>
<Text>A short project description.</Text>
</Stack>
}
/>Cached Layouts
Set cacheKey to reuse the last loaded layout for content that only exists after loading. fallback shows until a layout is cached. A fixture wins over the cache, and mask ignores it.
"use client";
import { Button, Skeleton, Stack, Text } from "@vortexlabs/vortex";
import { useState } from "react";
export const CachedContent = () => {
const [loading, setLoading] = useState(true);
return (
<Stack gap={4} width="100%">
<Skeleton
loading={loading}
cacheKey="docs-project-overview"
ariaLabel="Loading project overview"
fallback={<Skeleton width="60%" height={6} />}
>
{loading ? null : (
<Stack gap={2}>
<Text weight="medium">Project overview</Text>
<Text>Track milestones and recent updates.</Text>
</Stack>
)}
</Skeleton>
<Button variant="secondary" onClick={() => setLoading(!loading)}>
{loading ? "Show loaded project" : "Reload project"}
</Button>
</Stack>
);
};Blocks
Without children or a fixture, set width, height, and borderRadius to draw a block. Numbers use the spacing scale, strings take CSS lengths, and all three accept breakpoint objects. Blocks are fully rounded by default; set loading={false} to remove one.
<Stack direction="row" gap={6} align="center" wrap>
<Skeleton width={14} height={14} borderRadius="full" />
<Skeleton width="10rem" height="6rem" borderRadius="md" />
<Skeleton width="10rem" height={6} borderRadius="none" />
</Stack><Skeleton
width="100%"
height={{ xs: "8rem", md: "12rem" }}
borderRadius={{ xs: "sm", md: "lg" }}
/>Variants
The default shapes variant measures the content and draws separate shapes over it. mask paints the content itself instead: text becomes bars and media and controls become blocks, without measuring.
<Stack gap={6}>
<Skeleton variant="shapes" fixture={<Text>Project details are loading.</Text>} ariaLabel="Loading shapes example" />
<Skeleton variant="mask" fixture={<Text>Project details are loading.</Text>} ariaLabel="Loading mask example" />
</Stack>Animation
Choose pulse (the default), shimmer, or none. Add stagger to reveal generated shapes one after another; animations respect reduced motion preferences.
<Stack gap={3}>
<Skeleton width="60%" height={6} animation="pulse" />
<Skeleton width="60%" height={6} animation="shimmer" />
<Skeleton width="60%" height={6} animation="none" />
</Stack>Shape Measurement
Use measureOptions to skip elements with ignore, draw an element as one shape with block, or turn off surfaces, the lighter shapes drawn for cards. You can also mark elements with data-vortex-skeleton="ignore" or data-vortex-skeleton="block".
<Skeleton
ariaLabel="Loading project summary"
measureOptions={{ ignore: ["[data-project-updated]"], surfaces: false }}
fixture={
<Stack gap={2}>
<Text weight="medium">Project name</Text>
<Text>A short project description.</Text>
<Text attributes={{ "data-project-updated": true }}>Updated today</Text>
</Stack>
}
/>Content stays mounted while loading. In server-rendered HTML, filled elements keep their color until hydration; add data-vortex-skeleton="block" to mask them.
Accessibility
ariaLabel to describe what is loading.ariaLabel are silent to assistive tech. When several blocks stand in for one piece of content, give one of them an ariaLabel, not every block. With children or fixture, Skeleton hides the content and sets aria-busy itself.