Components
PreviousNext

Skeleton

Loading placeholder component with shimmer animations.

A skeleton component displays a placeholder while content is loading.

Installation

Copy and paste the following code into your project.

components/ui/skeleton.tsx
import { cn } from '@kit/shared';

export interface SkeletonProps {
    /**
     * Disable the shimmer animation.
     * 
     * @default false
    */
   noShimmer?: boolean;
   /**
     * Display an animated shimmer border.
     * 
     * @default false
     */
    shimmerBorder?: boolean;
    /**
     * Used by the extra wrapper added when `shimmerBorder` is true 
     */
    shimmerBorderClassName?: string;
}

function Skeleton({
    className,
    noShimmer = false,
    shimmerBorder = false,
    shimmerBorderClassName = '',
    style: styleProps,
    ...props
}: SkeletonProps & React.ComponentProps<'div'>) {

    const {
        animationDelay,
    } = styleProps || {};

    const content = (
        <div
            data-slot="skeleton"
            className={cn(
                'bg-accent rounded-md',
                noShimmer
                    ? 'animate-pulse'
                    : 'animate-shimmer shimmer-with-pulse [--shimmer-color:color-mix(in_oklab,var(--color-opposite)_8%,transparent_100%)] dark:[--shimmer-color:color-mix(in_oklab,var(--color-opposite)_3%,transparent_100%)]',
                className
            )}
            aria-label="Loading"
            style={styleProps}
            {...props}
        />
    );

    return shimmerBorder && !noShimmer ? (
        <div
            className={cn(
                'animate-shimmer rounded-[9px] p-px [--shimmer-color:color-mix(in_oklab,var(--color-opposite)_40%,transparent_100%)]',
                shimmerBorderClassName
            )}
            style={{animationDelay}}
        >
            <div className="bg-background rounded-md ">{content}</div>
        </div>
    ) : (
        content
    );
}

export { Skeleton };

Add the required shimmer animation styles to your globals.css file:

/* shimmer animation */ @keyframes shimmer-animation { 0% { background-position: var(--shimmer-start-x, -1000px) 0; } 100% { background-position: var(--shimmer-end-x, 1000px) 0; } } @theme { --animate-shimmer: shimmer-animation 2s linear infinite; } @utility shimmer-with-pulse { animation: shimmer-animation 2s linear infinite, var(--animate-pulse, pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite); } @utility animate-shimmer { --_shimmer-center: var(--shimmer-center, 0.65); /* 0.5 centered */ --_shimmer-width: var(--shimmer-width, 200px); --_shimmer-color: var( --shimmer-color, color-mix(in oklab, var(--color-opposite) 3%, transparent 100%) ); --_reference: 50%; --_shimmer-half-width: calc(var(--_shimmer-width) / 2); --_lower-breakpoint: calc(var(--_reference) - var(--_shimmer-half-width)); --_upper-breakpoint: calc(var(--_reference) + var(--_shimmer-half-width)); --_main-breakpoint: calc(var(--_lower-breakpoint) + var(--_shimmer-width) * var(--_shimmer-center)); background-image: linear-gradient( 110deg, transparent 0%, transparent var(--_lower-breakpoint), var(--_shimmer-color) var(--_main-breakpoint), transparent var(--_upper-breakpoint), transparent 100% ); background-size: cover; background-repeat: no-repeat; }

Update the import paths to match your project setup.

Usage

import { Skeleton } from '@kit/ui/skeleton';
<Skeleton className="w-48 h-4" />

Custom Shimmer Color

Customize the shimmer color using the --shimmer-color CSS variable:

API Reference

PropTypeDefault
noShimmer
boolean
false
shimmerBorder
boolean
false
shimmerBorderClassName
string

How is this guide?

Last updated on 11/26/2025