Skeleton

A skeleton acts as a placeholder for content, usually while the content loads.

A skeleton acts as a placeholder for content, usually while the content loads.

Basic

import React from 'react'; import Skeleton from '@atlaskit/skeleton'; export default (): React.JSX.Element => <Skeleton width="200px" height="16px" testId="skeleton" />;

Shimmering effect

The shimmering animation can be controlled via the isShimmering prop.

import React from 'react'; import Skeleton from '@atlaskit/skeleton'; export default (): React.JSX.Element => <Skeleton width="200px" height="16px" isShimmering />;

Customized shape

Use width, height, and borderRadius to control the shape.

import React from 'react'; import Skeleton from '@atlaskit/skeleton'; import { token } from '@atlaskit/tokens'; export default (): React.JSX.Element => ( <Skeleton width="40px" height="40px" borderRadius={token('radius.full')} /> );

Customized color

The default skeleton color can be overridden via the color prop.

import React from 'react'; import Skeleton from '@atlaskit/skeleton'; import { token } from '@atlaskit/tokens'; export default (): React.JSX.Element => ( <Skeleton width="200px" height="16px" color={token('color.background.accent.gray.subtle')} testId="skeleton" /> );

Customized shimmering animation color

The default shimmering animation from and to colors can be overridden via the color and ShimmeringEndColor prop.

import React from 'react'; import Skeleton from '@atlaskit/skeleton'; import { token } from '@atlaskit/tokens'; export default (): React.JSX.Element => ( <Skeleton width="200px" height="16px" color={token('color.background.accent.gray.subtle')} ShimmeringEndColor={token('color.background.accent.gray.bolder')} isShimmering /> );

Interaction tracing

When a Skeleton is given an interactionName, it holds the current UFO interaction while it is mounted and releases the hold when it unmounts. This keeps the interaction open while placeholder content is on screen, so performance metrics reflect the time users spend waiting for real content. This behaviour is enabled via the InteractionContext provided by UFO and is gated behind the platform-dst-skeleton-ufo-hold feature gate.

Interaction logNo events yet.
import React, { useCallback, useMemo, useState } from 'react'; import InteractionContext from '@atlaskit/interaction-context'; import { Box } from '@atlaskit/primitives/compiled/box'; import { Stack } from '@atlaskit/primitives/compiled/stack'; import { Text } from '@atlaskit/primitives/compiled/text'; import Skeleton from '@atlaskit/skeleton'; const INTERACTION_NAME = 'skeleton.example.content'; /** * Demonstrates how `@atlaskit/skeleton` participates in UFO interaction tracing. * * When a `Skeleton` is given an `interactionName`, it "holds" the current UFO * interaction (via `InteractionContext`) for as long as it is mounted, and releases * the hold when it unmounts. This keeps the interaction open while placeholder * content is on screen, so performance metrics reflect the time users spend waiting * for real content. * * In a real app the `InteractionContext.Provider` is supplied by UFO. Here we provide * a lightweight stand-in that surfaces the hold/release lifecycle on screen so the * otherwise-invisible behaviour is observable. Toggle the button to mount/unmount the * skeleton and watch the interaction be held and then released. */ export default function SkeletonInteractionTracing(): React.JSX.Element { const [isLoading, setIsLoading] = useState(true); const [log, setLog] = useState<string[]>([]); const appendLog = useCallback((message: string) => { setLog((current) => [...current, message]); }, []); const hold = useCallback( (name?: string) => { appendLog(`Held interaction: ${name ?? '(unnamed)'}`); return () => { appendLog(`Released interaction: ${name ?? '(unnamed)'}`); }; }, [appendLog], ); // The context value must have a stable identity. `Skeleton` re-runs its // hold/release effect whenever the context object changes, so recreating this // object on every render (e.g. as an inline literal) would release and re-hold // the interaction in a loop each time the log updates. const contextValue = useMemo(() => ({ hold, tracePress: () => {} }), [hold]); return ( <InteractionContext.Provider value={contextValue}> <Stack space="space.150" alignInline="start"> <button type="button" onClick={() => setIsLoading((value) => !value)}> {isLoading ? 'Finish loading (unmount skeleton)' : 'Start loading (mount skeleton)'} </button> {isLoading ? ( <Skeleton width="200px" height="16px" interactionName={INTERACTION_NAME} /> ) : ( <Text>Content loaded</Text> )} <Box backgroundColor="color.background.neutral.subtle" padding="space.150"> <Stack space="space.050"> <Text weight="bold">Interaction log</Text> {log.length === 0 ? ( <Text color="color.text.subtle">No events yet.</Text> ) : ( log.map((entry, index) => ( <Text key={index} color="color.text.subtle"> {entry} </Text> )) )} </Stack> </Box> </Stack> </InteractionContext.Provider> ); }
Was this page helpful?
We use this feedback to improve our documentation.
  • Design system
    • Get started
    • Foundations
    • Components
    • Rovo UI
    • Tools
    • Release phases
    • Contact us
© 2026 AtlassianTrademark, (opens new window)Privacy, (opens new window)License