Loading Button

A button that displays a loading indicator and prevents interaction while an asynchronous action is in progress.
Stable
Web
iOS
Android
@advui/core
Source
JSX
<LoadingButton loadingText="Saving…">Save</LoadingButton>
spinnerPosition
variant
size

Installation

pnpm
pnpm add @advui/core
npm
npm install @advui/core

Usage

import { LoadingButton } from '@advui/core'

const [saving, setSaving] = useState(false)

const save = async () => {
  setSaving(true)
  try {
    await saveData()
  } finally {
    setSaving(false)
  }
}

<LoadingButton loading={saving} loadingText="Saving…" onPress={save}>
  Save
</LoadingButton>

Examples

Basic

Normal and loading.

Loading text

Say what is happening while the action runs.

Custom spinner

Spinner position

The spinner replaces the icon on its side: the leading icon on the left, `iconAfter` on the right.

Async operation

The parent sets `loading` around the request. Press it several times: presses while saving are ignored.
Not saved yet.

API reference

LoadingButton

Takes every Button prop (`variant`, `size`, `icon`, `iconAfter`, `fullWidth`, `disabled`, `onPress`, `theme`, style props…). Your app owns `loading`; the button only shows it and blocks presses.
PropTypeDefaultDescription
loadingbooleanfalseShows the spinner, sets `aria-busy` and ignores presses, clicks and keys. When false it is a plain Button.
loadingTextReactNode—Replaces the label while loading, e.g. "Saving…". Without it the label stays next to the spinner.
spinnerReactNode`<Spinner size="sm" />` in the label colorA custom indicator element. Icons take the button’s icon size and color.
spinnerPosition'left' | 'right''left'Side of the spinner. It takes the place of the icon on that side. With only `iconAfter`, it defaults to `'right'`.
disabledbooleanfalseWorks as on Button. While loading the button is disabled either way.

Accessibility

  • It is a Button: a native <button> on web and a button role on iOS and Android, named by its visible label.
  • While loading it is disabled and has aria-busy="true", so screen readers report it as busy and unavailable, and Enter, Space, clicks and taps do nothing.
  • The spinner is hidden from assistive technology so it does not change the button’s name. The name is the label, or loadingText while loading: use loadingText when the change should be heard.
  • Like any disabled <button>, it loses keyboard focus while loading on web. Announce the result (for example in a polite live region, as in the Async example) when the action finishes.
Keyboard interactions
KeyAction
Enter / SpaceActivates the button; ignored while loading.
TabMoves focus; a loading button is skipped.

Responsive behavior

Height, padding and radius come from size, so they do not change while loading. A longer loadingText widens the button; keep it about as long as the label.

Platform notes

Web
Uses the browser spinner SVG from Spinner.
iOS
The default spinner is the platform ActivityIndicator.
Android
Same as iOS; the ripple is off while loading.
Since v0.6.0Last updated Nov 2, 2026Edit this page on GitHub