The Skeleton component shows placeholder content while your actual data is loading, improving perceived performance and user experience.
Import
import { Skeleton } from '@naturacosmeticos/natds-web'
Basic Usage
Variants
Skeletons come in different shapes:
// Text skeleton (default)
<Skeleton variant="text" />
// Circular skeleton (for avatars, icons)
<Skeleton variant="circle" width="semix" height="semix" />
// Rectangular skeleton (for images, cards)
<Skeleton variant="rect" width="veryhuge" height="hugex" />
Custom Dimensions
Set custom width and height using theme size tokens:
<Skeleton width="veryhuge" height="medium" />
<Skeleton variant="circle" width="huge" height="huge" />
<Skeleton variant="rect" width="veryhuge" height="hugex" />
Animation Types
Control the animation style:
// Pulse animation (default)
<Skeleton />
// Wave animation
<Skeleton animation="wave" width="veryhuge" />
// No animation
<Skeleton animation={false} width="veryhuge" />
With Typography
Infer dimensions from child Typography components:
<>
<Skeleton />
<Typography variant="h1">
Skeleton with Heading level 1
</Typography>
</>
<>
<Skeleton />
<Typography variant="h3">
Skeleton with heading 3 example
</Typography>
</>
<>
<Skeleton />
<Typography variant="body1">
Skeleton with body1 example
</Typography>
</>
Loading Avatar
Use with Avatar components:
<>
<Skeleton variant="circle">
<Avatar src="/path/to/image.jpg" alt="User" />
</Skeleton>
</>
When you pass children, the Skeleton infers its width and height automatically.
Loading Cards
Create loading states for card layouts:
function CardSkeleton() {
return (
<div style={{ width: 300, padding: 16 }}>
<Skeleton variant="rect" width="100%" height={200} />
<Skeleton width="60%" style={{ marginTop: 16 }} />
<Skeleton width="80%" />
<Skeleton width="40%" />
</div>
)
}
Loading Lists
Create loading states for list items:
function ListSkeleton() {
return (
<div>
{[1, 2, 3, 4, 5].map((item) => (
<div key={item} style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
<Skeleton variant="circle" width="semix" height="semix" />
<div style={{ flex: 1 }}>
<Skeleton width="100%" />
<Skeleton width="60%" />
</div>
</div>
))}
</div>
)
}
Conditional Rendering
Show skeletons while loading:
function UserProfile() {
const [loading, setLoading] = useState(true)
const [user, setUser] = useState(null)
useEffect(() => {
fetchUser().then(data => {
setUser(data)
setLoading(false)
})
}, [])
if (loading) {
return (
<div>
<Skeleton variant="circle" width="huge" height="huge" />
<Skeleton width="80%" style={{ marginTop: 16 }} />
<Skeleton width="60%" />
</div>
)
}
return (
<div>
<Avatar src={user.avatar} />
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
)
}
Props
variant
'text' | 'rect' | 'circle'
default:"text"
The shape of the skeleton.
Width of the skeleton. Uses theme size tokens or CSS values.
Height of the skeleton. Uses theme size tokens or CSS values.
animation
'pulse' | 'wave' | false
default:"pulse"
The animation type. Set to false to disable animation.
Optional child component to infer dimensions from.
Accessibility
- Skeletons are purely presentational and don’t require specific ARIA attributes
- They help improve perceived performance by showing content structure immediately
- Screen readers will skip skeleton content and announce the real content when it loads
Best Practices
Match skeleton shapes and sizes to your actual content
Use wave animation for emphasis or pulse for subtlety
Display skeletons immediately while content loads
Show multiple skeleton items for list layouts
Don’t show skeletons for very fast loading times (less than 200ms) — it creates unnecessary flashing
Don’t use skeletons for error states — show error messages instead
Why Use Skeletons?
Skeletons improve the user experience by:
- Reducing perceived load time — Users feel like content is loading faster
- Preventing layout shift — The page structure is visible immediately
- Setting expectations — Users see what type of content is coming
- Maintaining engagement — Something is always visible, preventing blank screens
Read more: Avoid The Spinner
Implementation Details
- Component source:
/packages/web/src/Components/Skeleton/Skeleton.tsx:26
- Built on Material-UI’s Skeleton component
- Integrated with Natura’s theme system for consistent sizing
- Supports theme size tokens through the
getSizeStyleProp hook