---
description: "For declarative forms, the earlier form, whose own action hides them: it answers the agent's submit and keeps the form in place until the agent has its answer."
---

# `useToolAnswer`

For [declarative forms](/docs/more/declarative-forms), the earlier form, whose own action hides them: it answers the agent's submit and keeps the form in place until the agent has its answer. Chrome cancels a tool call whose definition changes mid-flight, and unmounting or un-naming a declarative form changes it.

A tool from [`useWebTool`](/docs/reference/react/use-web-tool) does not need it: its `execute` simply returns the answer, and the hook keeps the tool registered until the call is answered.

## Import

```ts
import { useToolAnswer } from "@webmcp-agents/react";
import type { ToolAnswer } from "@webmcp-agents/react";
```

## Example

Applying a code hides the form, so it stays for a moment after the agent's submit. `answer` takes the native event and the result as a promise.

```tsx title="components/apply-promo-form.tsx"
import { useToolAnswer } from "@webmcp-agents/react";
import type { FormEvent } from "react";

// A declarative form (the earlier form). Applying a code hides the
// form, so it stays for a moment after the agent's submit.
export function ApplyPromoForm({ applied }: { applied: boolean }) {
  const { answering, answer } = useToolAnswer();

  if (applied && !answering) return null;

  function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const code = new FormData(event.currentTarget).get("code");
    answer(
      event.nativeEvent as SubmitEvent,
      Promise.resolve(`Applied ${String(code)}.`),
    );
  }

  return (
    <form
      toolname="apply_promo"
      tooldescription="Apply a promo code to the cart."
      toolautosubmit=""
      onSubmit={onSubmit}
    >
      <input
        name="code"
        required
        toolparamdescription="The code, e.g. WELCOME10"
      />
      <button type="submit">Apply</button>
    </form>
  );
}
```

## Options

None. The hook takes no arguments.

## Returns

A `ToolAnswer`:

| Name | Type | Description |
|---|---|---|
| `answering` | `boolean` | True from an agent's submit until 500 ms (`RESPONSE_GRACE_MS`) after its result settles. Keep the form rendered meanwhile. |
| `answer(event, result)` | `(event: SubmitEvent, result: Promise<unknown>) => void` | Answers an agent-invoked submit: calls `event.respondWith(result)` and sets `answering`. Does nothing for a person's submit (`event.agentInvoked` is falsy). |

## Notes

- Pass the native event: in a React handler that is `e.nativeEvent as SubmitEvent`. `agentInvoked` and `respondWith` live on it.
- A rejected `result` also ends `answering` after the grace, without leaving a second unhandled rejection behind.
- A form that navigates away after answering should navigate after the grace too (`RESPONSE_GRACE_MS`, exported by core).
- Call `answer` synchronously in the submit handler. The polyfill reads the response when the event's dispatch returns, and answers `"Form submitted."` if none was given.
- `useAnswerGrace` is the same function under its old name. It is deprecated.

## See also

- [Tools with input](/docs/build/tools-with-input), the way new code writes a form
- [Declarative forms](/docs/more/declarative-forms)
- [JSX attributes](/docs/reference/react/jsx-attributes)
- [`useWebTool`](/docs/reference/react/use-web-tool)
- [`PolyfillModelContext`](/docs/reference/polyfill/polyfill-model-context) (declarative forms, `agentInvoked`, `respondWith`)
- [Tool error codes](/docs/reference/core/tool-error)
