<!-- Protocore Design System — InlineLoading -->
# InlineLoading

- **Category:** Feedback (`feedback`)
- **Slug:** `feedback/inline-loading`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { InlineLoading } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/feedback/inline-loading

> An inline spinner + label that resolves to a success check or an error cross, driven by a state prop.

## When to use it

**InlineLoading** is for the small, in-place feedback that belongs beside the control that triggered it — a "Saving… / Saved" beside a form button, a per-row upload state, an inline validation check. It keeps the outcome next to the cause instead of firing a toast across the screen.

For a blocking, full-surface wait use **LoadingOverlay**; for indeterminate progress with no resolution use **Spinner**; for a determinate bar use **ProgressBar**. Keep the success and error states on screen only briefly, then return to `idle` or remove the component.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `className` | `string` | no | — | — |
| `label` | `ReactNode` | no | — | The text shown beside the indicator. |
| `state` | `enum` | no | `loading` | Which phase to render. |
| `style` | `CSSProperties` | no | — | — |

## Examples

### The three states

`state` drives the indicator: `"loading"` shows a spinner, `"success"` a check, `"error"` a cross — each with its own `label`. The state is fully controlled by you, so it fits naturally at the end of a save or upload flow.

```tsx
import { InlineLoading } from "@protocore/pds";

export default function InlineLoadingStates() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12, alignItems: "flex-start" }}>
      <InlineLoading state="loading" label="Saving changes…" />
      <InlineLoading state="success" label="Changes saved" />
      <InlineLoading state="error" label="Save failed" />
    </div>
  );
}
```

### In a form action

Wire it next to a submit button: flip to `loading` on click, then to `success` or `error` when the request settles. The polite live region announces each transition to assistive tech.

```tsx
import * as React from "react";
import { InlineLoading, Button, type InlineLoadingState } from "@protocore/pds";

const LABEL: Record<InlineLoadingState, string> = {
  idle: "",
  loading: "Saving…",
  success: "Saved",
  error: "Failed — try again",
};

export default function InlineLoadingFlow() {
  const [state, setState] = React.useState<InlineLoadingState>("idle");

  const run = () => {
    setState("loading");
    window.setTimeout(() => setState("success"), 1400);
    window.setTimeout(() => setState("idle"), 3400);
  };

  return (
    <div style={{ display: "flex", gap: 16, alignItems: "center" }}>
      <Button size="sm" onClick={run} disabled={state === "loading"}>
        Save
      </Button>
      {state !== "idle" ? <InlineLoading state={state} label={LABEL[state]} /> : null}
    </div>
  );
}
```

## Usage

**Do**

- Place it beside the control that started the action.
- Change the `label` with the state ("Saving…" → "Saved").
- Return to `idle` (or unmount) shortly after resolving.
- Use the error state for the failure, then offer a retry.

**Don't**

- Leave a success check on screen indefinitely; it's a transient.
- Use it for a page-blocking wait; that's LoadingOverlay.
- Rely on the icon color alone — always pair it with a label.

## Accessibility

**Notes**

- The root is a polite live region (`role="status"`), so state transitions are announced without stealing focus.
- The check and cross are decorative SVGs (`aria-hidden`); the meaning is carried by the text label, never by color alone.

## Related

`spinner`, `progress-bar`, `loading-overlay`, `notification`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
