---
title: Skeleton
description: Use Skeleton to show where content will appear while it is loading.
version: 11.17.0
generatedAt: 2026-11-05T09:55:46.318Z
checksum: 38d7202a365da531b3702e62d932ac6c2e55e712321889f177c476f349dee300
---

# Skeleton

## Import

```tsx
import { Skeleton } from '@dnb/eufemia'
```

## Description

The Skeleton component is a visual building block that helps provide loading placeholders. It displays a non-interactive preview of the actual UI of the component, visually communicating that content is being processed.

After 2 seconds, the animation starts and runs for 20 cycles of 2 seconds each. It then stops, leaving solid placeholders until loading finishes. The animation is disabled when `noAnimation` is set or reduced motion is requested.

## Relevant links

- [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/skeleton)
- [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/web/components/skeleton)

## Take into consideration

It should be used carefully and not as a quick loading indicator replacement. The browser will use additional resources to render the additional state. If it is misused, such as showing a significantly different UI or being shown for just a fraction of a second, it can distract from the user experience rather than enhancing it.

Also, in some setups, the user may need to download almost the entire web application before skeletons can be shown during API calls.

### Prerendered pages

A prerendered setup is a good fit to utilize a strong skeleton user experience from the very first page visit. Every page can load quickly, and we can take advantage of this by showing our skeleton as the initial state.

1. The skeletons will show up during the very first paint – even without JavaScript enabled.
1. Next, our page loads the needed application bundle, so we can start an API call to get our user data.
1. Now our application renders.
1. Finally, we have the user data to display.

## Accessibility

- Elements and components should still be responsive to screen width and font size.
- Screen readers will get a mention that the loading state has finished as an aria-live update.
- Components and interactive elements are not accessible for keyboard users.

## When not to use

- For low-traffic pages, such as super-user-only admin pages, use a loading spinner instead.
- For a tiny, inline action or feedback, e.g. clicked a button and the action will take time, use the [ProgressIndicator](/web/components/progress-indicator) instead (animation).
- For fast processes that take less than `300ms`, consider the [ProgressIndicator](/web/components/progress-indicator) or no loading state at all.
- For a background process or a long-running process, e.g. importing data or exporting reports, use the [ProgressIndicator](/web/components/progress-indicator) instead (percentage).

## When to use

- Use on high-traffic pages and landing pages, if they require a loading state.
- Use when there’s more than one element loading at the same time that requires an indicator.
- Use when the process would take more than `300ms` to load on an average internet connection.
- Use the Skeleton component when the [ProgressIndicator](/web/components/progress-indicator) is not prominent enough.

## How to use

You can use the Skeleton component as a provider for all underlying components, like inputs and buttons. This way, you can simply toggle on and off the skeletons. And all the spacing and sizing will be given from the components themselves.

But you can also use the Skeleton component to show a fake article or other figures.

## How it works

Every Eufemia component should support a skeleton natively. But for simplification, you can use the Skeleton component as a provider to enable the skeletons for a group of components.

If you use the skeleton as a provider, the [Space](/web/layout-and-typography/layout/space) component is used as a wrapper. This wrapper also helps the underlying components to define the style type or animation. If only the defaults are used, then you can skip it by setting the element to `false` with `element={false}`.

But the Skeleton component also supports a set of ready-to-use figures. Use it like `figure="article"`.


```tsx
render(<Div id="your-app">
      <Skeleton show={true}>
        <Input>I'm hidden behind the skeleton</Input>
        <Input>I'm hidden behind the skeleton</Input>
      </Skeleton>
    </Div>)
```


## Global Provider

You can also use the global [Eufemia Provider](/web/styling-and-themes/configuration/provider) to enable the underlying skeletons. You can even have multiple providers wrapped.


```tsx
render(<Provider locale="nb-NO">
      <Div id="your-app">
        <Provider skeleton={true}>
          <Input>I'm hidden behind the skeleton</Input>
          <Input>I'm hidden behind the skeleton</Input>
        </Provider>
      </Div>
    </Provider>)
```


## Exclude a part

You can easily exclude a part from being transformed to a skeleton by using `Skeleton.Exclude`.


```tsx
render(<Skeleton show={true}>
      <Input>I'm hidden behind the skeleton</Input>

      <Skeleton.Exclude>
        <Input>I'm NOT hidden</Input>
      </Skeleton.Exclude>
    </Skeleton>)
```


## Suspense

You can take advantage of an async component by using the React Suspense with a skeleton fallback.


```tsx
render(<Suspense fallback={<Skeleton show={true}>
          <Div id="user-data" />
        </Skeleton>}>
      <Div id="user-data" />
    </Suspense>)
```


## Create a custom skeleton

In order to create the same skeletons as the build-ins, you can make use of a couple of helper tools.


```tsx
function Component({
  skeleton = false,
  ...params
} = {}) {
  const context = useContext(Context);

  // Handle accessibility features
  skeletonDOMAttributes(params, skeleton, context);

  // Handle CSS classes – use either "shape" or "font"
  const className = createSkeletonClass('font', skeleton, context);
  return <div {...params} id="my-component" className={className}>
            Hello World
          </div>;
}
render(<Component />);
```


## Generate a skeleton font

Skeleton fonts replace glyph outlines with blocks while retaining the source
font's glyph advances, kerning, substitutions and embedded line metrics. Generate
them from the font files used by the stylesheet, not an older font with a similar
name. In particular, keep the `hhea`, OS/2 typo and Windows metrics, and the
`USE_TYPO_METRICS` flag together: browsers select and round these differently
across Windows, Linux and macOS.

From `packages/dnb-eufemia`, regenerate the DNB Text and Mono skeletons with:

```shell
yarn skeleton:font
```

This command runs once, reads the official fonts in `assets/fonts/dnb/`, and
writes Light, Regular, Medium and Bold in OTF, TTF, WOFF and WOFF2 to
`assets/fonts/dnb/skeleton/`. It does not modify the source fonts or download ZIPs.

It also generates the single upright Display skeleton from
`assets/fonts/dnb/DNBSansDisplay.ttf`. Display keeps its own source metrics;
it must not reuse a Text skeleton.

To generate a skeleton from another TTF or OTF:

```shell
yarn skeleton:font --source path/to/font.ttf --output path/to/skeletons --family CustomSkeleton --prefix Custom-Skeleton --style Regular
```

Register the generated family with `@font-face` and verify font loading, widths,
wrapping, line boxes and baselines against the source font in each supported
browser. Identical inline font-box rounding across operating systems is not
guaranteed, even when the paragraph line height and baseline are unchanged.


## Related components

Skeleton is part of the [Feedback and dialogs](/web/components/overview/#feedback) category. More components in this category:

- [Badge](/web/components/badge/) – to highlight new, unread, or important information.
- [Dialog](/web/components/dialog/) – when people need to make a choice or read an important message before continuing.
- [Drawer](/web/components/drawer/) – to show extra content in a panel that slides in from the side.
- [Form status](/web/components/form-status/) – to show validation errors, warnings, or messages near a form.
- [Global error](/web/components/global-error/) – to show a clear 404 or 500 error page.
- [Global status](/web/components/global-status/) – to show important page-level messages or a summary of form errors.

[See all in Feedback and dialogs](/web/components/overview/#feedback)


## Demos

<PortalSkeleton />

## Input with Skeleton


```tsx
render(<Input label="Input" skeleton />)
```


## Toggle skeleton on/off


```tsx
const UserData = () => {
  const [state, setState] = useState(true);
  return <Skeleton show={state}>
            <H2 top bottom>
              Heading
            </H2>
            <P top bottom>
              Paragraph Non habitasse ut nisi dictum laoreet ridiculus dui.
            </P>
            <Input label="Input" />
            <Skeleton.Exclude>
              <ToggleButton checked={state} onChange={({
        checked
      }) => setState(checked)} top="large">
                Toggle
              </ToggleButton>
            </Skeleton.Exclude>
          </Skeleton>;
};
render(<UserData />);
```


## Skeleton wrapper


```tsx
render(<Skeleton show>
      <H2 top bottom>
        Heading
      </H2>
      <P top bottom>
        Paragraph Non habitasse ut nisi dictum laoreet ridiculus dui.
      </P>
      <Button>Button</Button>
    </Skeleton>)
```


## Skeleton using Eufemia Provider

You can also use `formElement={{ skeleton: true }}`.


```tsx
render(<Provider skeleton={true}>
      <H2 top bottom>
        Heading
      </H2>
      <P top bottom>
        Paragraph Non habitasse ut nisi dictum laoreet ridiculus dui.
      </P>
      <Button>Button</Button>
    </Provider>)
```


## Skeleton figures

You may import a given figure, or create your own.

```jsx
import { Article } from '@dnb/eufemia/components/skeleton/figures'
```


```tsx
render(<Skeleton show figure={<Article rows={5} />}>
      hidden content
    </Skeleton>)
```



  
```tsx
<Skeleton show noAnimation>
      <AllComponentsHorizontalTestCase layoutEngine="legacy" data-visual-test="skeleton-all-horizontal" />
    </Skeleton>
<Skeleton show noAnimation>
      <AllComponentsVerticalLabelsTestCase layoutEngine="legacy" data-visual-test="skeleton-all-vertical" />
    </Skeleton>
```

<!-- eufemia-properties-usage:start -->
Some properties provide flexibility for specific integrations. Follow the component's usage guidance. Customizations beyond the documented patterns need a use case approved by DNB UX. [Read about intended use and customization](/web/styling-and-themes/configuration/component-properties/#intended-use-and-customization).
<!-- eufemia-properties-usage:end -->

## Properties


```json
{
  "props": {
    "show": {
      "doc": "Use `true` to enable/show the skeleton for the component used inside. Defaults to `false`.",
      "type": "boolean",
      "status": "optional"
    },
    "figure": {
      "doc": "Define a figure to use, like `article`. The wrapped content will be hidden while the skeleton figure is shown.",
      "type": [
        "string",
        "React.Element",
        "function"
      ],
      "status": "optional"
    },
    "noAnimation": {
      "doc": "Use `true` to disable the animation.",
      "type": "boolean",
      "status": "optional"
    },
    "ariaBusy": {
      "doc": "Is used for screen reader text translation, defined in the translation files. You can set a custom text if needed.",
      "type": "string",
      "status": "optional"
    },
    "ariaReady": {
      "doc": "Is used for screen reader text translation, defined in the translation files. You can set a custom text if needed.",
      "type": "string",
      "status": "optional"
    },
    "element": {
      "doc": "Set any HTML element type you have to use. A couple of aria attributes will be set on this element while active. Defaults to `div`.",
      "type": [
        "string",
        "React.Element"
      ],
      "status": "optional"
    },
    "[Space](/web/layout-and-typography/layout/space/properties)": {
      "doc": "Spacing properties like `top` or `bottom` are supported.",
      "type": [
        "string",
        "object"
      ],
      "status": "optional"
    }
  },
  "usageGuidance": "Some properties provide flexibility for specific integrations. Follow the component's usage guidance. Customizations beyond the documented patterns need a use case approved by DNB UX. [Read about intended use and customization](/web/styling-and-themes/configuration/component-properties/#intended-use-and-customization)."
}
```


## Translations


```json
{
  "locales": [
    "da-DK",
    "en-GB",
    "nb-NO",
    "sv-SE"
  ],
  "entries": {
    "Skeleton.ariaBusy": {
      "nb-NO": "Behandler data ...",
      "en-GB": "In progress ...",
      "sv-SE": "Bearbetar data ...",
      "da-DK": "Behandler data ..."
    },
    "Skeleton.ariaReady": {
      "nb-NO": "Klar til å samhandle",
      "en-GB": "Ready to interact",
      "sv-SE": "Klar att interagera",
      "da-DK": "Klar til at interagere"
    }
  }
}
```
