Best for
- Lazy-loaded panels (side panels, detail views)
- Fetcher-driven content swaps
- Async data sections (lists, profiles, detail views)
gaia-react/gaia/.claude/skills/skeleton-loaders/SKILL.md
For building skeleton loading states that are pixel-perfect matches of real content. Use this skill whenever adding loading states to components, building skeletons for async data, handling pending loader states in route transitions, or implementing the shimmer animation pattern. Also trigger when the user asks about preventing layout shift during data fetching.
Decision brief
Build skeleton loading states that are pixel-perfect matches of real content.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/gaia-react/gaia --skill ".claude/skills/skeleton-loaders"Inspect the Agent Skill "skeleton-loaders" from https://github.com/gaia-react/gaia/blob/395b416ee24619690a051c4dbcf9dcd20895e95b/.claude/skills/skeleton-loaders/SKILL.md at commit 395b416ee24619690a051c4dbcf9dcd20895e95b. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Review the “Full Example Implementation” section in the pinned source before continuing.
Use real HTML elements (, , , ) with the same font classes as the real component, plus shimmer + transparency classes. This makes skeletons inherit exact line-height, font-size, and weight, producing pixel-perfect dimensions without hardcoded h-/w- values.
Define a shared class string at the top of the skeleton component:
Copy the real component's element type and font classes, add shimmer. How you fill the text depends on whether the real text is static or dynamic:
Keep as empty divs with the shimmer class, no text needed:
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 84/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 21 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Build skeleton loading states that are pixel-perfect matches of real content.
Use real HTML elements (<p>, <span>, <h2>, <button>) with the same font classes as the real component, plus shimmer + transparency classes. This makes skeletons inherit exact line-height, font-size, and weight, producing pixel-perfect dimensions without hardcoded h-*/w-* values.
Define a shared class string at the top of the skeleton component:
const shimmer =
'animate-shimmer rounded-sm bg-linear-to-r from-slate-950 via-slate-900 to-slate-950 bg-size-[200%_100%] text-transparent select-none';
Copy the real component's element type and font classes, add shimmer. How you fill the text depends on whether the real text is static or dynamic:
t() value the real component uses. The text is transparent, but reusing t() makes the skeleton width match the revealed text exactly.{data.name}, API content): you cannot know the real value, so use hardcoded placeholder text of similar character count to approximate its width.import {twJoin} from 'tailwind-merge';
// Real component
<h2 className="text-lg font-bold text-white">{t('profile.heading')}</h2> // static
<p className="truncate text-sm font-semibold text-white">{data.name}</p> // dynamic
<p className="text-xs text-slate-400">{data.value}</p> // dynamic
// Skeleton
<h2 className={twJoin('text-lg font-bold', shimmer)}>{t('profile.heading')}</h2> // same t(), exact width
<p className={twJoin('truncate text-sm font-semibold', shimmer)}>Name</p> // approximate
<p className={twJoin('text-xs', shimmer)}>Example value</p> // approximate
Keep as empty divs with the shimmer class, no text needed:
<div className={twJoin('size-14 shrink-0', shimmer)} />
Use the real element type with tabIndex={-1} to prevent focus. Button labels are static text, so use the real t() value (exact width on reveal):
<button
className={twJoin('w-full py-2 text-xs font-medium', shimmer)}
tabIndex={-1}
type="button"
>
{t('common.submit')}
</button>
Avoid skeleton flash on fast loads. Show stale/empty content for 200ms before revealing the skeleton:
const [showSkeleton, setShowSkeleton] = useState(false);
// Valid Effect: synchronizing component state with a timer (external system).
// The cleanup prevents a state update after unmount.
useEffect(() => {
const timer = setTimeout(() => setShowSkeleton(true), 200);
return () => clearTimeout(timer);
}, []);
if (!showSkeleton) return null; // or return stale content
return <MySkeleton />;
Skeleton text is transparent, but screen readers still announce it (placeholder text and any t() labels). Hide the skeleton from assistive tech and announce loading instead:
aria-hidden on the skeleton's root element so assistive tech skips the decorative placeholders.aria-busy="true" while loading, or render a visually-hidden role="status" "Loading" message so screen-reader users know content is on the way.import {twJoin} from 'tailwind-merge';
const shimmer =
'animate-shimmer rounded-sm bg-linear-to-r from-slate-950 via-slate-900 to-slate-950 bg-size-[200%_100%] text-transparent select-none';
const ExampleSkeleton = () => (
<div aria-hidden className="border border-slate-700 bg-slate-900">
<div className="flex items-center gap-3 p-3">
<div className={twJoin('size-14 shrink-0', shimmer)} />
<div className="min-w-0 flex-1">
<p className={twJoin('truncate text-sm font-semibold', shimmer)}>
Name
</p>
<p className={twJoin('truncate text-xs', shimmer)}>Example value</p>
</div>
</div>
</div>
);
export default ExampleSkeleton;
Alternatives
coreyhaines31/marketingskills
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program
coreyhaines31/marketingskills
When the user wants to reduce churn, build cancellation flows, set up save offers, recover failed payments, or implement retention strategies. Also use when the user mentions 'churn,' 'cancel flow,' 'offboarding,' 'save offer,' 'dunning,' 'failed payment recovery,' 'win-back,' 'retention,' 'exit survey,' 'pause subscription,' 'involuntary churn,' 'people keep canceling,' 'churn rate is too high,' 'how do I keep users,' or 'customers are leaving.' Use this whenever someone is losing subscribers o
JasonColapietro/suede-creator-skills
Suede-owned experimentation discipline for hypotheses, sample sizing, test duration, significance, and repeatable experiment programs. Use when comparing variants, deciding whether a result is reliable, or building an experiment backlog and cadence. NOT FOR: analytics instrumentation (use suede-analytics), post-click conversion diagnosis (use suede-site-alchemy), or writing the variant copy itself (use suede-copy).
narrative-io/narrative-skills-marketplace
Translate a fuzzy analytical question into a rigorous investigation plan. Interrogates the ask, grounds the plan in the available data dictionary, applies analytical best practices, and produces a structured brief of query specifications for a downstream query-writing skill. Plans, does not write SQL. Use when: "why did X drop", "is there a relationship between A and B", "who are our highest-value customers", "what's driving the change in Y", "investigate this trend", "design an analysis for", "