Vanilla Breeze

data-loading

Button loading state with spinner, aria-busy, double-submit prevention, and auto-revert. Upscales the native disabled attribute for async actions.

Overview

The data-loading attribute on a <button> upscales the native disabled state into a full loading experience: a spinner replaces the button text, aria-busy is set for screen readers, and clicks are blocked to prevent double-submit. For submit buttons inside a form, the loading state activates automatically on form submission.

How It Works

When activated, the enhancement:

  1. Preserves layout — Locks the button width to prevent shift when content changes.
  2. Shows a spinner — Replaces button content with an animated spinner and optional loading text.
  3. Sets accessibility state — Adds aria-busy="true" and disabled.
  4. Auto-reverts — Restores original content when the action completes or after a safety timeout.

Attributes

Attribute Value Description
data-loading empty or text Enable loading enhancement. Optional value is the loading text (e.g. "Saving..."). Empty shows spinner only.
data-loading-timeout number Auto-revert after N milliseconds. Default: 10000 (10 seconds).

Form Integration

Submit buttons inside a <form> automatically activate on form submission. When paired with the form coordinator (data-submit="fetch"), the button auto-reverts when the submission completes.

For native form submissions (which navigate away), the loading state persists until the page navigates — which is the correct behavior.

Programmatic Control

For buttons outside forms or async actions, control the loading state via the JavaScript API:

You can also toggle via the data-loading-active attribute:

Button Variants

The spinner inherits currentColor, so it works with all button variants:

Accessibility

During loading:

  • aria-busy="true" tells screen readers the button action is in progress.
  • disabled prevents keyboard and pointer activation.
  • The spinner is marked aria-hidden="true" so it doesn’t interfere with screen reader output.
  • The spinner animation slows to 1.5s under prefers-reduced-motion.

Containers vs Buttons

The data-loading attribute serves two purposes depending on the element:

Element Visual Behavior
Container (<section>, <div>) Shimmer overlay, skeleton CSS-only, no JS needed
Button (<button>) Inline spinner, disabled state JS-enhanced with auto-revert