AdminKitDocs
Components

React Bootstrap Placeholders

React Bootstrap placeholder markup in AdminKit PRO: a loading card with the same layout as the real one, widths, sizes, colors and glow or wave animation.

Pro

This component is only available in AdminKit PRO. Learn more.

Placeholders are gray blocks in the shape of text and buttons. Show them while a card or a list waits for its data: the page has its final layout from the start, and nothing jumps when the content arrives.

They are Bootstrap's .placeholder classes in JSX, so there is no component to import. You render a placeholder version of your component while its data is missing, then the real one. Placeholders are part of the PRO version of AdminKit for React.

For charts, maps and plugins, AdminKit uses the Skeleton component instead.

Example

The placeholders demo shows a card next to its loading version, with the same size and layout:

<div className="row">
  <div className="col-6">
    <div className="card">
      <div className="card-body">
        <h2 className="card-title">Website redesign</h2>
        <p className="card-text">
          New landing pages and a lighter checkout, due at the end of the quarter.
        </p>
        <a href="#" className="btn btn-primary">Open project</a>
      </div>
    </div>
  </div>
  <div className="col-6">
    <div className="card" aria-hidden="true">
      <div className="card-body">
        <h2 className="card-title placeholder-glow">
          <span className="placeholder col-6" />
        </h2>
        <p className="card-text placeholder-glow">
          <span className="placeholder col-7" />{" "}
          <span className="placeholder col-4" />{" "}
          <span className="placeholder col-4" />{" "}
          <span className="placeholder col-6" />
        </p>
        <a
          href="#"
          tabIndex={-1}
          className="btn btn-primary disabled placeholder col-6"
          aria-disabled="true"
        />
      </div>
    </div>
  </div>
</div>

The {" "} between the spans keeps the space that separates them in HTML, so they wrap like words. Empty elements close themselves in JSX: <span className="placeholder col-6" />.

Classes

ClassEffect
placeholderA block in the current text color, at reduced opacity
col-<n>, w-25 to w-100The width; or a style={{ width: "25%" }} object
placeholder-lg, placeholder-sm, placeholder-xsThe height; by default it follows the font size of the parent
bg-<color>Another color than the text color
placeholder-glow, placeholder-waveOn the parent: a pulsing or a sweeping animation

On a .btn, placeholder keeps the button's height. Add disabled and tabIndex={-1}, so it cannot be clicked or focused.

While data loads

Write the placeholder version as its own small component, next to the real one. When you change the layout of one, the other is right there to change too:

import { useEffect, useState } from "react";

type Project = { name: string; summary: string };

function ProjectCardPlaceholder() {
  return (
    <div className="card" aria-hidden="true">
      <div className="card-body">
        <h2 className="card-title placeholder-glow">
          <span className="placeholder col-6" />
        </h2>
        <p className="card-text placeholder-glow">
          <span className="placeholder col-7" /> <span className="placeholder col-4" />
        </p>
      </div>
    </div>
  );
}

export function ProjectCard({ id }: { id: string }) {
  const [project, setProject] = useState<Project | null>(null);

  useEffect(() => {
    fetch(`/api/projects/${id}`)
      .then((response) => response.json())
      .then(setProject);
  }, [id]);

  return (
    <div aria-busy={project === null}>
      {project === null ? (
        <ProjectCardPlaceholder />
      ) : (
        <div className="card">
          <div className="card-body">
            <h2 className="card-title">{project.name}</h2>
            <p className="card-text">{project.summary}</p>
          </div>
        </div>
      )}
    </div>
  );
}

For a list or a table, render a fixed number of placeholder rows with Array.from({ length: 3 }, (_, index) => ...) and the index as the key, since the rows have no data yet.

Sizes, colors and animation

Set the height with a size class and the color with a bg- class. The animation class goes on the parent:

<>
  <p className="placeholder-glow mb-2"><span className="placeholder col-12 placeholder-lg" /></p>
  <p className="placeholder-glow mb-2"><span className="placeholder col-12" /></p>
  <p className="placeholder-glow mb-2"><span className="placeholder col-12 placeholder-sm bg-primary" /></p>
  <p className="placeholder-wave mb-0"><span className="placeholder col-12 placeholder-xs bg-success" /></p>
</>

Placeholders or Skeleton

  • Use placeholders for content you write in markup: cards, lists, table rows, profile headers. They copy the layout of the real content.
  • Use Skeleton (@/components/ui/skeleton) for content that a library draws in the browser, such as a chart or a map. The plugin wrappers render it themselves until they are ready.

Accessibility

  • Hide the placeholder version from screen readers with aria-hidden="true": its blocks have no text to read.
  • Mark the region that loads with aria-busy while the data is missing, as in the example above.
  • Placeholder buttons get tabIndex={-1} and aria-disabled="true", so keyboard users do not land on them.

Last updated on

On this page