FAQ & Troubleshooting
General Questions
Does it work with SSR (Next.js, Remix)?
AutoSkeleton requires a real DOM for measurement, so skeletons are generated client-side only. In SSR frameworks:
- The first render will show your actual content (or nothing if data isn't available)
- Once hydration completes and
loading={true}, the skeleton appears - This means there may be a brief flash before the skeleton shows on the initial page load
For SSR-critical pages, consider combining AutoSkeleton with server-rendered placeholder content.
Does it work with CSS-in-JS libraries?
Yes. AutoSkeleton reads computed styles from the DOM, so it works with any styling approach:
- Inline styles
- CSS Modules
- Tailwind CSS
- styled-components
- Emotion
- Vanilla CSS
Does it work with component libraries (MUI, Ant Design, Chakra)?
Yes, for most components. AutoSkeleton measures the final rendered DOM, so it's agnostic to which library generated it. Complex components with portals, virtualization, or heavy JavaScript rendering may not measure correctly.
What's the bundle size?
The library is ~19 KB unminified, ~5 KB gzipped. It has zero runtime dependencies beyond React.
Performance
Is there a performance cost?
Yes, there's a measurement cost on every loading transition:
- DOM traversal: Walks the element tree calling
getBoundingClientRect()andgetComputedStyle() - Blueprint generation: Builds the skeleton node tree
- Rendering: React renders the skeleton overlay
For typical UI (< 200 elements), this takes < 10ms. For very large DOMs (500+ elements), consider:
- Reducing
maxDepthto limit traversal - Wrapping smaller sections individually instead of the entire page
- Using
data-skeleton-ignoreon complex subtrees that don't need skeletons
Can I use it with virtualized lists?
No. Virtualized lists (react-virtualized, tanstack-virtual, react-window) only render visible items in the DOM. AutoSkeleton can't measure elements that aren't rendered. For virtualized content, use traditional skeleton components.
What's the maximum recommended DOM size?
AutoSkeleton works well up to ~500 elements. Beyond that, measurement time may become noticeable. For large pages, wrap individual sections rather than the entire page:
// Instead of this:<AutoSkeleton loading={loading}> <EntirePage /> {/* might have 1000+ elements */}</AutoSkeleton>// Do this:<Header /><AutoSkeleton loading={loading}> <MainContent /> {/* focused section, ~100 elements */}</AutoSkeleton><Sidebar />Troubleshooting
Elements are misclassified
If AutoSkeleton renders the wrong skeleton type for an element:
- Quick fix: Add
data-skeleton-role="correct-type"to force the right classification - Check dimensions: Very small elements (< 100px^2) may be classified as
skip - Check display: Elements with
display: flexordisplay: gridare treated as containers, not leaves
Skeleton doesn't match the layout
- Ensure your elements have explicit dimensions or content during loading. Empty elements have no size to measure.
- For images, provide
widthandheightattributes or CSS dimensions. Images with nosrcand no dimensions will measure as 0x0. - For async data, provide placeholder content during loading (see Table Support).
Layout shift when toggling loading
AutoSkeleton uses an overlay approach to minimize layout shift. If you still see shifts:
- Ensure the wrapping container has stable dimensions
- Avoid
width: 100%on the root children without a constrained parent - The skeleton overlay is absolutely positioned — the content layer determines the container size
Elements disappear during loading
If an element is completely gone during loading:
- Check if it has
.no-skeletonclass ordata-skeleton-ignore— these skip the element from the skeleton - Use
data-no-skeletoninstead if you want the element to remain visible during loading
Skeleton appears briefly then disappears
This usually means loading is toggling quickly. Ensure your data fetching logic keeps loading={true} until data is fully ready:
// Correctconst [loading, setLoading] = useState(true);useEffect(() => { fetchData().then(data => { setData(data); setLoading(false); // Only set false when data is ready });}, []);Known Limitations
- Client-side only — Requires a real DOM; no SSR skeleton generation
- Heuristic-based — Misclassification possible on unusual layouts; use
data-skeleton-roleto fix - No virtualization support — Can't measure elements not in the DOM
- Performance ceiling — Large DOMs (500+ elements) may have noticeable measurement time
- Cannot predict content — Skeleton dimensions match placeholder/initial content, not the final loaded data
- Single animation — Currently supports
pulseandnone; shimmer is not yet implemented - No `<colgroup>` support — Table column groups are not explicitly handled