---
title: 'Ai.AgentAction'
description: 'Shows an agent action progressing, its result, and an optional Undo.'
version: 11.17.0
generatedAt: 2026-11-05T09:55:47.089Z
checksum: 88daede5c08df2585a8434f641cfcd38e212d87c31e27ac72a4d682a4bc7f22d
---

# Ai.AgentAction

**Experimental:** The AI extension and its component APIs may change in the future. Please give us feedback on your experience with them.

## Import

```tsx
import { AgentAction } from '@dnb/eufemia/extensions/ai'
import '@dnb/eufemia/extensions/ai/style'

render(<AgentAction>Generating a graph…</AgentAction>)
```

## Description

`Ai.AgentAction` shows a compact action row with a decorative agent avatar, an animated progress pill, and a result. It can also show Undo with a countdown. The design follows [Agent Action in Figma](https://www.figma.com/design/A8EvkeqtDzsdh1UhiTQbSQ/-Draft--AI-Components?node-id=71010-1526).

Use it for actions such as paying a bill or generating a graph when you need progress, a short text result and optional Undo. [Ai.Task](/web/patterns-and-extensions/ai/Task/) also shows an operation and its outcome, but accepts details, decision controls and structured results below a status row. Choose by the interaction you need, rather than whether the operation comes from an agent or a framework tool. See [Choosing Task or AgentAction](/web/patterns-and-extensions/ai/integrations/#choosing-task-or-agentaction).

### Controlling an action

The application owns execution, authorization, progress, and the result. Map your framework's state to `running`, `done`, `error`, or `canceled`, and supply text describing the current state. The component does not start or complete an action.

While running, `actionLabel` is an optional verb before the pill and `children` is the text inside it. For example, use `actionLabel="Paying"` with `children="Spotify Premium"`. When the state changes, replace `children` with the result, such as `Spotify Premium paid.`. The verb and pill disappear.

Pass `progress` from 0 to 100 when the application knows the actual progress. Omit it when the progress is unknown. A value of 100 still shows a running action until the application confirms `status="done"`. Do not infer success from elapsed time or an animation ending. Use a separate component instance or React key for each action.

### Offering Undo

Provide `onUndo` only when the application can reverse a completed action. It is shown only for `status="done"`. The callback receives the Eufemia Button click event; the application performs the reversal and updates the text and state once the outcome is known. Set `undoDisabled` while a reversal is pending, and present any failure in your application.

For a time-limited reversal, pass `undoUntil` as an absolute Unix timestamp in milliseconds, preferably from the action result. The countdown uses the clock, so re-rendering or mounting an existing action does not restart the time window. Undo disappears at the deadline, and a late click is ignored. The application must still enforce the deadline when handling the request. Without `undoUntil`, Undo stays available until the application removes `onUndo` or changes the state.

### Accessibility and motion

The component announces status and text changes through Eufemia AriaLive, including changes to `children` while the status stays the same. Announcements are polite and atomic, with a one-second debounce. Keep the component mounted and update its props. Use short, complete status messages rather than streaming text into the action label.

When Undo becomes available, the announcement includes the button label and any remaining time limit. The button description gives a stable, localized expiry time. Expiry is announced once; countdown ticks and progress updates do not trigger live announcements. A progressbar exposes its name and percentage when known, or an indeterminate state when progress is unknown.

Set `announce={false}` for historical actions or when your application owns announcements. This silences initial and subsequent announcements while preserving the content, progress semantics, and button description. Avoid wrapping AgentAction in another live region while its own announcements are enabled.

The Undo control uses Eufemia Button and returns focus to the action status if it becomes disabled or expires while focused. It preserves focus elsewhere. In forced-colors mode, the fill has a boundary using the system text color. Reduced motion disables the animation while preserving the state and percentage. The running text keeps its normal color.

Your application supplies meaningful, translated action and result text, changes the status when execution or reversal finishes, and presents any errors. It also owns confirmation, authorization, and enforcement of the Undo deadline. Assess whether a time limit is appropriate and provide a longer window or another reversal mechanism when needed. The component does not announce changes to other content elsewhere in your application.

The `agentAvatar` identifies the agent to the left of the action row. It defaults to Aino; set `agentAvatar={false}` to hide it. The `targetVisual` appears beside the target text inside the progress pill and accepts an Avatar, icon, or image. A small [Avatar](/web/components/avatar/) with `hasLabel` works in either position. Both visuals are decorative; use the text to identify the action and result.


## Demos

### Agent action states


```tsx
render(<Provider locale="en-GB">
        <Flex.Stack>
          <AgentAction actionLabel="Paying" announce={false} progress={35} targetVisual={<Avatar size="small" src={spotifyAvatar} alt="" hasLabel />}>
            Spotify Premium
          </AgentAction>
          <AgentAction actionLabel="Paying" announce={false} progress={65} agentAvatar={<Avatar size="small" icon={solve} variant="tertiary" hasLabel />} targetVisual={<Avatar size="small" src={spotifyAvatar} alt="" hasLabel />}>
            Spotify Premium
          </AgentAction>
          <AgentAction announce={false}>Generating a graph…</AgentAction>
          <AgentAction status="done" announce={false}>
            Spotify Premium paid.
          </AgentAction>
          <AgentAction status="error" announce={false}>
            Payment failed. Please try again.
          </AgentAction>
          <AgentAction status="canceled" announce={false}>
            Graph generation canceled.
          </AgentAction>
        </Flex.Stack>
      </Provider>)
```


### Known progress and timed Undo

This example simulates a confirmed payment and a reversible result. Its timers belong to the demo application. Production progress and completion must come from the actual action.


```tsx
const PaymentDemo = () => {
  const [progress, setProgress] = useState(0);
  const [status, setStatus] = useState<AiAgentActionStatus>('running');
  const [undoUntil, setUndoUntil] = useState<number>();
  useEffect(() => {
    if (status !== 'running') {
      return undefined;
    }
    const started = Date.now();
    const interval = setInterval(() => {
      const value = Math.min(100, (Date.now() - started) / 22);
      setProgress(value);
      if (value === 100) {
        // Simulate a confirmed result with a 20-second reversal window.
        clearInterval(interval);
        setUndoUntil(Date.now() + 20000);
        setStatus('done');
      }
    }, 110);
    return () => clearInterval(interval);
  }, [status]);
  return <Provider locale="en-GB">
              <Flex.Stack>
                <AgentAction actionLabel="Paying" progress={progress} status={status} targetVisual={<Avatar size="small" src={spotifyAvatar} alt="" hasLabel />} undoUntil={undoUntil} onUndo={() => setStatus('canceled')}>
                  {status === 'running' ? 'Spotify Premium' : status === 'done' ? 'Spotify Premium paid.' : 'Payment reversed.'}
                </AgentAction>
                <Button variant="secondary" disabled={status === 'running'} onClick={() => {
        setProgress(0);
        setUndoUntil(undefined);
        setStatus('running');
      }}>
                  Replay payment
                </Button>
              </Flex.Stack>
            </Provider>;
};
render(<PaymentDemo />);
```


### Unknown progress and cancellation

Use indeterminate progress until the application receives a result. The controls here simulate completion and cancellation.


```tsx
const GraphDemo = () => {
  const [status, setStatus] = useState<AiAgentActionStatus>('running');
  return <Provider locale="en-GB">
              <Flex.Stack>
                <AgentAction status={status}>
                  {status === 'running' ? 'Generating a graph…' : status === 'done' ? 'Graph generated.' : 'Graph generation canceled.'}
                </AgentAction>
                <Flex.Horizontal>
                  <Button disabled={status !== 'running'} onClick={() => setStatus('done')}>
                    Complete graph
                  </Button>
                  <Button variant="secondary" disabled={status !== 'running'} onClick={() => setStatus('canceled')}>
                    Cancel graph
                  </Button>
                  <Button variant="tertiary" icon={false} disabled={status === 'running'} onClick={() => setStatus('running')}>
                    Restart graph
                  </Button>
                </Flex.Horizontal>
              </Flex.Stack>
            </Provider>;
};
render(<GraphDemo />);
```


### Pending Undo

Disable Undo while the application handles a reversal. Confirm the outcome before updating the result. This demo lets you simulate that response or add a deadline to an existing Undo control.


```tsx
const UndoDemo = () => {
  const [pending, setPending] = useState(false);
  const [reversed, setReversed] = useState(false);
  const [undoUntil, setUndoUntil] = useState<number>();
  return <Provider locale="en-GB">
              <Flex.Stack>
                <AgentAction status={reversed ? 'canceled' : 'done'} undoDisabled={pending} undoUntil={undoUntil} onUndo={() => setPending(true)}>
                  {reversed ? 'Payment reversed.' : pending ? 'Reversing payment…' : 'Spotify Premium paid.'}
                </AgentAction>
                <Flex.Horizontal>
                  <Button disabled={!pending} onClick={() => {
          setPending(false);
          setReversed(true);
        }}>
                    Confirm reversal
                  </Button>
                  <Button onClick={() => setUndoUntil(Date.now() + 20000)}>
                    Add Undo deadline
                  </Button>
                  <Button onClick={() => {
          setPending(false);
          setReversed(false);
          setUndoUntil(undefined);
        }}>
                    Reset payment
                  </Button>
                </Flex.Horizontal>
              </Flex.Stack>
            </Provider>;
};
render(<UndoDemo />);
```


### Historical actions

Use `announce={false}` when rendering saved conversation history. The content stays available to screen-reader navigation without announcing each past action on mount.


```tsx
render(<Provider locale="en-GB">
        <Flex.Stack>
          <AgentAction status="done" announce={false}>
            Earlier payment completed.
          </AgentAction>
          <AgentAction status="canceled" announce={false}>
            Earlier graph generation canceled.
          </AgentAction>
        </Flex.Stack>
      </Provider>)
```

<!-- eufemia-properties-usage:start -->
Some properties provide flexibility for specific integrations. Follow the component's usage guidance. Customizations beyond the documented patterns need a use case approved by DNB UX. [Read about intended use and customization](/web/styling-and-themes/configuration/component-properties/#intended-use-and-customization).
<!-- eufemia-properties-usage:end -->

## Properties


```json
{
  "props": {
    "status": {
      "doc": "Display status supplied by the application. Progress never changes the status automatically.",
      "type": [
        "\"running\"",
        "\"done\"",
        "\"error\"",
        "\"canceled\""
      ],
      "defaultValue": "\"running\"",
      "status": "optional"
    },
    "actionLabel": {
      "doc": "The action verb shown before the progress pill while running, e.g. `Paying`.",
      "type": "string",
      "status": "optional"
    },
    "children": {
      "doc": "The target text while running, or the action result, e.g. `Spotify Premium` while running and `Spotify Premium paid.` when done.",
      "type": "string",
      "status": "required"
    },
    "agentAvatar": {
      "doc": "Decorative agent avatar. Defaults to a small Aino Avatar. Use `false` to hide it.",
      "type": "React.ReactNode",
      "status": "optional"
    },
    "targetVisual": {
      "doc": "Decorative content beside the target text inside the progress pill, such as an Avatar, icon, or image.",
      "type": "React.ReactNode",
      "status": "optional"
    },
    "progress": {
      "doc": "Progress from 0 to 100. Omit it when progress is unknown. Values are clamped; non-finite values use indeterminate progress.",
      "type": "number",
      "status": "optional"
    },
    "undoUntil": {
      "doc": "Absolute Unix timestamp in milliseconds for the Undo deadline. Without it, Undo remains available until the application removes `onUndo`.",
      "type": "number",
      "status": "optional"
    },
    "undoLabel": {
      "doc": "Undo button text. Defaults to a translated text.",
      "type": "string",
      "status": "optional"
    },
    "undoDisabled": {
      "doc": "Disable Undo while the application handles the request.",
      "type": "boolean",
      "status": "optional"
    },
    "announce": {
      "doc": "Announce status, text, and Undo availability changes. Set to false for historical actions or when the application owns announcements.",
      "type": "boolean",
      "defaultValue": "true",
      "status": "optional"
    },
    "[Space](/uilib/layout/space/properties)": {
      "doc": "Spacing properties like `top` or `bottom` are supported.",
      "type": [
        "string",
        "object"
      ],
      "status": "optional"
    }
  },
  "usageGuidance": "Some properties provide flexibility for specific integrations. Follow the component's usage guidance. Customizations beyond the documented patterns need a use case approved by DNB UX. [Read about intended use and customization](/web/styling-and-themes/configuration/component-properties/#intended-use-and-customization)."
}
```


## Translations

| Key                         | Purpose                                                                                            |
| --------------------------- | -------------------------------------------------------------------------------------------------- |
| `undo`                      | Undo button label.                                                                                 |
| `undoTimeLeft`              | Label for the quiet countdown.                                                                     |
| `undoAvailable`             | Announces availability. `%action` is the button label.                                             |
| `undoAvailableFor`          | Announces a time limit. `%action` is the button label and `%seconds` is the remaining time.        |
| `undoAvailableForOneSecond` | Singular form of the time-limit announcement.                                                      |
| `undoAvailableUntil`        | Stable button description. `%action` is the button label and `%time` is the localized expiry time. |
| `undoUnavailable`           | Announces expiry. `%action` is the button label.                                                   |

Status announcements reuse the [Ai.Task translations](/web/patterns-and-extensions/ai/Task/properties/#translations). Application-specific action and result text must be translated by the application. See [AI translations](/web/patterns-and-extensions/ai/translations/).

## Events


```json
{
  "props": {
    "onUndo": {
      "doc": "Called when Undo is clicked before its deadline. Receives the Button click event. Only available when `status` is `done`; the application handles the reversal and updates the display.",
      "type": "function",
      "status": "optional"
    }
  }
}
```
