# Action Toggle (/docs/action-toggle)

An asynchronous toggle that commits its pressed state only after the action succeeds.

## Install

```bash
npx shadcn@latest add https://4af.selfsimilar.dev/r/action-toggle.json
```

## Usage

```tsx
import { ActionToggle } from "@/components/ui/action-toggle";

<ActionToggle action={(following) => setFollowing(following)}>
  Follow
</ActionToggle>
```

## API

**Main export:** `ActionToggle`

A toggle that runs an async `action` and changes state only when it succeeds. Use it for states
such as Follow/Following or Subscribe/Subscribed.

`loader={<MySpinner />}` supplies the pending indicator. Otherwise it inherits
[LoaderProvider](/docs/reference/engineering#shared-loading-indicators), defaulting to `AsciiLoader`.
A supplied `icons.pending` takes precedence.

## Persistent state

[Action Button](/docs/action-button) shows a temporary outcome, then returns to idle.
Use Action Toggle when the new state should persist:

```tsx
<ActionToggle
  action={(following) => (following ? follow(id) : unfollow(id))}
  icon={<Plus />}
  icons={{ pressed: <Check /> }}
  labels={{ pressed: "Following" }}
>
  Follow
</ActionToggle>
```

It sets `aria-pressed`, which is why it is a separate component, as Toggle is from Button.

It is not optimistic. The label stays and the loader runs until the action settles. On failure it
shows the error briefly and keeps its previous state. `onPressedChange` fires only on success.

With `fillIcon` and no `icons.pressed`, the same glyph fills when pressed instead of being
replaced.