All components
Skeleton
Loading placeholders with pulse and shine animations that respect reduced motion.
12345678910111213141516import { Skeleton } from "#components/ui/ark-ui/skeleton.tsx";
export function Example({ loaded }: { loaded: boolean }) { return ( <> {/* variant + loading props resolve through the StyleX recipe */} <Skeleton variant="pulse" />
{/* flip loading off to fade the loaded content back in; asChild wraps your real element */} <Skeleton asChild variant="shine" loading={loaded ? "false" : "true"}> <p>Ready when you are.</p> </Skeleton> </> );}Variants
pulse
shine
none
Install
1npx stylexblocks add skeletonSource
components/ui/ark-ui/skeleton.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475import * as stylex from "@stylexjs/stylex";import { createComponent } from "#lib/ark-ui/create-component.tsx";import { defineRecipe } from "#lib/recipe-props.ts";import { semanticColors } from '@stylexblocks/ui/semantic-tokens/colors.stylex.ts'import { semanticRadii } from '@stylexblocks/ui/semantic-tokens/radii.stylex.ts'
const skeletonStyles = stylex.create({ base: {},})
const skeletonLoadings = stylex.create({ true: { borderRadius: semanticRadii.panel, boxShadow: 'none', backgroundClip: 'padding-box', cursor: 'default', color: 'transparent', pointerEvents: 'none', userSelect: 'none', flexShrink: 0, }, false: { backgroundColor: 'unset', animationName: 'fade-in', animationDuration: 'var(--fade-duration, 0.1s)', animationTimingFunction: 'ease-out', },})
const skeletonVariants = stylex.create({ pulse: { backgroundColor: semanticColors.bgEmphasized, animationName: 'pulse', animationTimingFunction: 'cubic-bezier(0.4, 0, 0.6, 1)', animationIterationCount: 'infinite', animationDuration: 'var(--duration, 1.2s)', }, shine: { '--animate-from': '200%', '--animate-to': '-200%', '--start-color': semanticColors.bgMuted, '--end-color': semanticColors.bgEmphasized, backgroundImage: 'linear-gradient(270deg,var(--start-color),var(--end-color),var(--end-color),var(--start-color))', backgroundSize: '400% 100%', animationName: 'bg-position', animationDuration: 'var(--duration, 5s)', animationTimingFunction: 'ease-in-out', animationIterationCount: 'infinite', }, none: { animationName: 'none', backgroundColor: semanticColors.bgMuted, },})
export type SkeletonLoading = keyof typeof skeletonLoadings
export type SkeletonVariant = keyof typeof skeletonVariants
/** * Skeleton — recipe and component colocated in one file. Variant and * loading props resolve mechanically from the axis maps (`loading="false"` * fades the loaded content back in). Composition via `asChild`. */const skeletonRecipe = defineRecipe({ styles: skeletonStyles, axes: { variant: skeletonVariants, loading: skeletonLoadings }, defaultVariants: { variant: "pulse", loading: "true" },});
export const Skeleton = createComponent("div", skeletonRecipe, "Skeleton");
export type SkeletonProps = React.ComponentProps<typeof Skeleton>;