# Activity Indicator

`ActivityIndicator` communicates an **indeterminate** activity the user cannot
directly control or measure — loading, fetching, or waiting on an external
system.

Use `ActivityIndicator` when the loading time or fraction of progress is
unknown. If you know the fraction of progress (for example, "3 of 4 files
uploaded"), use `ProgressBar` instead. A `ProgressIndicator` counterpart that
will subsume `ProgressBar` under the new Indicators naming is forthcoming.

## Design & usage guidelines

The default `ActivityIndicator` size is `base` (44px) and can be used in most
cases. The `small` size (28px) should be used on individual elements of an
interface (e.g. inside a `Button` or `Card`) or when sitting next to short
inline text.

Layout is the consumer's responsibility — `ActivityIndicator` does not expose an
`inline` prop. Place it inside your own flex / inline-block container, or pass a
`style`, to control surrounding layout.

## Accessibility

`ActivityIndicator` announces itself to assistive technology on every platform:

* `accessibilityRole="progressbar"` and `accessibilityState={{ busy: true }}`
  mark the component as an ongoing indeterminate activity.
* `accessibilityLabel` defaults to a localized `"Loading"` string via
  `useAtlantisI18n("loading")`. Pass a custom `accessibilityLabel` to describe
  the specific activity (e.g. `accessibilityLabel="Uploading file"`).
* On mount and whenever the label changes, the component calls
  `AccessibilityInfo.announceForAccessibility` so VoiceOver and TalkBack
  announce the label once.

The indicator is not focusable and is not in the accessibility navigation order
beyond the mount-time announcement.

### Reduced motion

When the operating system reports the Reduce Motion accessibility setting, the
indicator hides the rocking and rotating layers, repaints a single static ring
in the icon foreground colour, and gently pulses its opacity so the indicator
still reads as "busy" without rotational motion. Detection is reactive — the
component responds to OS toggles without requiring a remount.

## Cross-platform parity

`ActivityIndicator` renders the same Material Design 3 three-layer indeterminate
ring on iOS, Android, and web (`@jobber/components`). The visual identity,
sizes, motion durations, and reduced-motion fallback are unified across
platforms. Public prop names diverge to follow each platform's native
conventions (`accessibilityLabel` here vs `ariaLabel` on web; `style` here vs
`className` + `style` on web).

Use `ActivityIndicator` when the loading time or fraction of progress is
unknown. If you know the fraction of progress (for example, "3 of 4 files
uploaded"), use `ProgressBar` instead. A `ProgressIndicator` counterpart that
will subsume `ProgressBar` under the new naming is forthcoming.

## Design & usage guidelines

The default `ActivityIndicator` size is `base` (32px) and can be used in most
cases. The `small` size (16px) should be used on individual elements of an
interface (e.g. inside a `Button` or `Card`) or when sitting next to short
inline text.

Layout is the consumer's responsibility — `ActivityIndicator` does not expose
an `inline` prop. Place it inside your own flex / inline-block container, or
pass a `className` / `style`, to control surrounding layout.

## Accessibility

`ActivityIndicator` announces itself politely to assistive technology:

* `role="status"` marks the element as a polite live region, appropriate for
  a non-urgent loading state.
* `aria-label` defaults to the literal English string `"Loading"`. Pass a
  custom `ariaLabel` to localize or to describe the specific activity
  (e.g. `ariaLabel="Uploading file"`).

The indicator does not participate in the keyboard tab order.

### Reduced motion

When the user's operating system reports
[`prefers-reduced-motion: reduce`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion),
the indicator hides its rocking and rotating layers, repaints a single
static ring in the icon foreground colour, and gently pulses its opacity so
the indicator still reads as "busy" without rotational motion.

## Relationship to Spinner

The legacy [Spinner](../Spinner/Spinner.md) component remains available and
unchanged. New code should prefer `ActivityIndicator`. A follow-up change is
expected to deprecate `Spinner` in favour of `ActivityIndicator`.

## Mobile

On mobile (`@jobber/components-native`), `ActivityIndicator` uses the
[ActivityIndicator](https://reactnative.dev/docs/activityIndicator) core
component from React Native.

## Mockup


## Props

### Web

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `ariaLabel` | `string` | No | `Loading` | Accessible label exposed via `aria-label` on the root element. Override to localize or to describe the specific activ... |
| `className` | `string` | No | — | Custom class name merged onto the root element alongside the component's own classes. |
| `size` | `"base" | "small"` | No | `base` | Visual size. `base` renders at 32px, `small` renders at 16px. |
| `style` | `CSSProperties` | No | — | Custom inline styles applied to the root element. |
