# Skeleton (Caseroom component)

A loading placeholder with a slow sheen that stands still under reduced motion. Black and white, dark mode, shadcn-compatible; React, Astro and plain HTML.

## Install

- React: `npx shadcn@latest add https://www.themes.dev/caseroom/r/skeleton.json`
- Astro: `npx shadcn@latest add https://www.themes.dev/caseroom/r/astro/skeleton.json`
- HTML: https://www.themes.dev/caseroom/r/html/skeleton.html (with https://www.themes.dev/caseroom/r/html/caseroom.css)

Page: https://www.themes.dev/caseroom/components/skeleton/ · Rules for agents: https://www.themes.dev/caseroom/AGENT.md

## Code

### skeleton.astro

```astro
---
import type { HTMLAttributes } from 'astro/types';
import { cn } from '@/lib/utils';
import { skeletonClasses } from './skeleton.variants';

type Props = HTMLAttributes<'span'>;
const { class: className, ...rest } = Astro.props;
---

<span aria-hidden="true" class={cn(skeletonClasses, className)} {...rest}></span>
```

### skeleton.tsx

```tsx
import type { HTMLAttributes } from 'react';
import { cn } from '@/lib/utils';
import { skeletonClasses } from './skeleton.variants';

export type SkeletonProps = HTMLAttributes<HTMLSpanElement>;

/** A loading placeholder. Size it with classes (h-4 w-32, size-10 rounded-full); mark the region aria-busy. */
export function Skeleton({ className, ...props }: SkeletonProps) {
  return <span aria-hidden="true" className={cn(skeletonClasses, className)} {...props} />;
}
```

### skeleton.variants.ts

```tsx
/** A placeholder while content loads: a muted block with a slow sheen. With reduced motion it is a still block. Wrap them
 *  in role="status" aria-busy="true" with a visually hidden "Loading …"; the skeletons themselves are hidden. */
export const skeletonClasses =
  'block rounded-md bg-muted bg-[linear-gradient(90deg,transparent,color-mix(in_oklab,var(--background)_55%,transparent),transparent)] bg-[length:200%_100%] bg-no-repeat animate-[caseroom-sheen_1.6s_ease-in-out_infinite] motion-reduce:animate-none';

/** The keyframes, once in your CSS (the Caseroom theme has them). */
export const SHEEN_KEYFRAMES = '@keyframes caseroom-sheen { from { background-position: 150% 0 } to { background-position: -50% 0 } }';
```
