FeedbackAvailable
Skeleton
Outlined loading placeholders composed into a full profile card, with an optional pulse and reduced-motion support.
Installation
Add the component and its dependencies from the registry running on your computer.
terminal
npx shadcn@latest add https://brutallab.facilito.dev/r/skeleton.jsonUsage
Import the component into your project and keep the source code under your control.
tsx
'use client';
import { useState } from 'react';
import { Skeleton } from '@/components/ui/skeleton';
import { Button } from '@/components/ui/button';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { Card } from '@/components/ui/card';
export default function Demo() {
const [loading, setLoading] = useState(true);
const [following, setFollowing] = useState(false);
return (
<div className="grid w-full min-w-0 max-w-lg gap-6">
<Card aria-busy={loading} className="min-h-72 gap-5 p-5">
{loading ? <>
<div className="flex items-center gap-4"><Skeleton className="size-10 shrink-0 rounded-full" /><div className="grid flex-1 gap-2"><Skeleton className="h-4 w-3/4" /><Skeleton className="h-3 w-1/2" /></div></div>
<div className="grid gap-2"><Skeleton className="h-3 w-full" /><Skeleton className="h-3 w-5/6" /><Skeleton className="h-3 w-2/3" /></div>
<Skeleton className="mt-auto h-11 w-32" />
</> : <>
<div className="flex items-center gap-4"><Avatar tone="purple"><AvatarFallback>AN</AvatarFallback></Avatar><div><strong className="font-medium">Ana Rivera</strong><p className="bl-type-small text-muted-foreground">Product designer · Study Club</p></div></div>
<p className="bl-type-small">Interfaces con carácter, pequeñas ideas y espacio para aprender. Construyendo una pieza a la vez.</p>
<Button variant="accent" className="mt-auto w-fit" aria-pressed={following} onClick={() => setFollowing(!following)}>{following ? 'Siguiendo / Following' : 'Seguir / Follow'}</Button>
</>}
</Card>
<output className="bl-type-small" aria-live="polite">{loading ? 'Loading profile / Cargando perfil' : 'Profile ready / Perfil listo'}</output>
<Button variant="outline" className="h-auto min-h-11 w-fit max-w-full whitespace-normal py-2 text-center" onClick={() => setLoading(!loading)}>{loading ? 'Show content / Mostrar contenido' : 'Show loading / Mostrar carga'}</Button>
<div className="grid gap-3"><p className="bl-type-label">Static / Sin animación</p><Skeleton animated={false} className="h-4 w-full" /><Skeleton animated={false} className="h-4 w-2/3" /></div>
</div>
);
}
States & interaction
Appearance, behavior and keyboard checks.
- Animated or static loading with animated={false}. Respects prefers-reduced-motion.
- No focus or hover. Shapes are hidden from screen readers; the container announces loading once and reserves final content space.
API Reference
BrutalLab-specific properties. Native attributes are supported as well.
| Prop | Type | Default | Description |
|---|---|---|---|
| animated | boolean | true | Pulse while loading. false gives a static placeholder. Reduced motion always disables animation. |
| className | string | — | Set the width, height and shape to reserve the space of the final content. |
Accessibility
Rules that should remain intact when adapting the component to a product.
Announce loading once on the container. Do not expose each placeholder as meaningful content.
Retain keyboard focus styles and test the composition with keyboard navigation.
Use className for visual customization; preserve the primitive ARIA attributes.