> ## Documentation Index
> Fetch the complete documentation index at: https://developer.suki.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Audio Dictation In Web SDK For React

> Learn how to use dictation in the Suki Web SDK for React applications

This guide walks you through the process of integrating the Suki Web SDK for audio dictation in a React application (browser-based) using the React package provided by Suki.

You will create **Auth Manager** and **Dictation Client** (typically inside **`useMemo`** so they are not recreated every render), wrap your tree with **Dictation Provider**, and render **Dictation** when the user should dictate.

Let's get started!

## Prerequisites

Before you begin, you must have the following requirements met:

* **Packages:** Install **`@suki-sdk/react`**, **`@suki-sdk/core`**.
* **Partner credentials:** Obtain **`partnerId`** and **`partnerToken`** from Suki after [Partner onboarding](/documentation/partner-onboarding).
* **Browser and layout:** Your app runs in a **browser**, with a real DOM and enough layout for the dictation UI.

Refer to [Prerequisites](/web-sdk/prerequisites) guide for more details.

## Install the packages

Add the following packages to the same project you load in the browser:

<CodeGroup title="Install @suki-sdk/dictation-react, @suki-sdk/dictation, @suki-sdk/core">
  ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  pnpm add @suki-sdk/core @suki-sdk/react 
  ```

  ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  yarn add @suki-sdk/core @suki-sdk/react 
  ```

  ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
  npm install @suki-sdk/core @suki-sdk/react 
  ```
</CodeGroup>

<Tip>
  After you install, pull the SDK into your files with **`import`**, the same way as in the examples below. Use whatever approach your project already uses for other npm libraries.
</Tip>

## Step 1: Add container and field layout

For this example we will assume you are using **`in-field`** mode as your preferred mode.

In **`in-field`** mode you need **two** parts in the UI: a **`div`** (or similar) that you can pass as **`rootElement`**, where the dictation controls show up, and a **textarea** (or input) that **`onSubmit`** will update when the user finishes.

The dictation layer **matches the size of** **`rootElement`** when you set it, so that node should have a **height** you control. Refer to [Wrapper layout](/dictation-sdk/guides/configuration#wrapper-layout) guide for recommended markup and CSS.

**Code example for container and field layout**

```jsx React  theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
<div id="clinical-notes-dictation-root" style={{ minHeight: 120 }} />
<label htmlFor="clinical-notes">Clinical notes</label>
<textarea id="clinical-notes" rows={8} />
```

Wire **`value`**, **`onChange`**, and your start button in the same component (see Step 5).

## Step 2: Create auth manager

Now you need to create the **Auth Manager** for your application. To create the Auth Manager, you must have the **`partnerId`** and **`partnerToken`** credentials from Suki.

Refer to [Partner onboarding](/documentation/partner-onboarding) guide to learn how to get these credentials.

In React you usually create the auth manager **inside** the same **`useMemo`** as the dictation client (see Step 3), so both exist once per page or shell. The snippet below shows only the auth piece for clarity.

**Code example for creating auth manager**

```javascript JavaScript expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
import { SukiAuthManager } from "@suki-sdk/core";

const authManager = new SukiAuthManager({
  partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required
  partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required
  environment: "staging", // optional: "staging" | "production"
  loginOnInitialize: true, // optional: sign in as soon as this runs
  autoRegister: false, // optional: enable provider auto-registration
  providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system
  providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name
  providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system
  providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty
});
```

## Step 3: Create dictation client

After you have created the auth manager, you can create the **dictation client** for your application. The Dictation Client is the object the React components use under the hood.

Create **one** dictation client and reuse it for the whole tree under **`DictationProvider`**. Use **`useMemo`** with an empty dependency array so you do **not** run **`new DictationClient(...)`** on every render.

**Code example for creating dictation client in React**

```jsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
import { useMemo } from "react";
import { SukiAuthManager } from "@suki-sdk/core";
import { DictationClient } from "@suki-sdk/react";

const client = useMemo(() => {
  const authManager = new SukiAuthManager({
    partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required
    partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required
    environment: "staging", // optional: "staging" | "production"
    loginOnInitialize: true, // optional: sign in as soon as this runs
    autoRegister: false, // optional: enable provider auto-registration
    providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system
    providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name
    providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system
    providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty
  });
  return new DictationClient({ authManager });
}, []);
```

## Step 4: Wrap with DictationProvider

Pass the **`client`** from Step 3 into **`DictationProvider`**. Every component that renders **`<Dictation>`** must be a **child** of that provider.

**Code example for wrapping with DictationProvider**

```jsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
import { DictationProvider } from "@suki-sdk/react";

export function App() {
  const client = useMemo(/* ... Step 3 ... */, []);

  return (
    <DictationProvider client={client}>
      {/* children that render <Dictation /> */}
    </DictationProvider>
  );
}
```

You can put **`DictationProvider`** at app root or only around the screen that needs dictation.

## Step 5: Render Dictation

Render **`<Dictation>`** only while that field should own the session (for example when the user clicked "Start dictation"). When **`<Dictation>`** unmounts, the SDK calls **`hide()`** for you.

Pass **`mode`**, **`fieldId`**, **`initialText`**, **`onSubmit`**, and any optional props you need. Refer to [Configuration](/dictation-sdk/guides/configuration) guide for more details on the available options and how to use them.

**Code example for rendering Dictation in React**

```jsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
import { useState } from "react";
import { Dictation } from "@suki-sdk/react";

function NotesEditor() {
  const [notes, setNotes] = useState("");
  const [dictationActive, setDictationActive] = useState(false);

  return (
    <>
      <textarea
        id="clinical-notes"
        value={notes}
        onChange={(e) => setNotes(e.target.value)}
      />
      <button
        type="button"
        onClick={() => setDictationActive((v) => !v)}
      >
        {dictationActive ? "Stop dictation" : "Start dictation"}
      </button>
      {dictationActive && (
        <Dictation
          fieldId="clinical-notes"
          mode="in-field"
          initialText={notes}
          onSubmit={({ text }) => setNotes(text)}
          onCancel={() => setDictationActive(false)}
        />
      )}
    </>
  );
}
```

<Tip>
  You can also drive dictation with a single **`activeFieldId`** string and render one **`<Dictation>`** when it matches, which scales to multiple fields.
</Tip>

<Note>
  **`onSubmit`** is required for a good user experience. If you omit it, dictation often **closes immediately** after the user acts.
</Note>

## Callbacks

Props such as **`onSubmit`**, **`onCancel`**, and **`onDraft`** receive the same shape as in the JavaScript API:

```jsx React  theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
{ fieldId: string, 
text: string 
}
```

Refer to [Callbacks](/dictation-sdk/guides/callbacks) guide for more details on the available callbacks and how to use them.

<Note>
  You do not poll for text; the SDK calls your functions when the user commits or cancels, and may call **`onDraft`** when they move on without submitting (refer to [Callbacks](/dictation-sdk/guides/callbacks) guide for more details).
</Note>

## Switching fields

Use the same **`client`** and **`DictationProvider`**. Change which field is active by updating state (for example **`activeFieldId`**) so only one **`<Dictation>`** is mounted, or swap **`fieldId`** / **`initialText`** on the next mount. You do **not** need to call **`hide()`** yourself just to move from one field to another when unmounting one **`<Dictation>`** and mounting another is how your UI switches.

## Unmounting and hiding

When **`<Dictation>`** unmounts, the SDK **automatically** calls **`hide()`**. You do not need to call **`hide()`** yourself for normal React flows.

## Complete code example

Below is a complete code example in React for in-field mode with **`DictationProvider`**, a toggle button, and one field.

```jsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
import { useMemo, useState } from "react";
import { SukiAuthManager } from "@suki-sdk/core";
import { DictationClient } from "@suki-sdk/react";
import { DictationProvider, Dictation } from "@suki-sdk/react";

export function NotesWithDictation() {
  const client = useMemo(() => {
    const authManager = new SukiAuthManager({
      partnerId: "YOUR_PARTNER_ID", // replace with your partner ID - required
      partnerToken: "YOUR_PARTNER_TOKEN", // replace with your partner token - required
      environment: "staging", // optional: "staging" | "production"
      loginOnInitialize: true, // optional: sign in as soon as this runs
      autoRegister: false, // optional: enable provider auto-registration
      providerId: "YOUR_PROVIDER_ID", // optional: provider identifier in your system
      providerName: "YOUR_PROVIDER_NAME", // optional: full provider display name
      providerOrgId: "YOUR_PROVIDER_ORG_ID", // optional: organization identifier for the provider in your system
      providerSpecialty: "YOUR_PROVIDER_SPECIALTY", // optional: clinical specialty
    });
    return new DictationClient({ authManager });
  }, []);

  const [notes, setNotes] = useState("");
  const [dictationActive, setDictationActive] = useState(false);

  return (
    <DictationProvider client={client}>
      <textarea
        id="clinical-notes"
        value={notes}
        onChange={(e) => setNotes(e.target.value)}
      />
      <button
        type="button"
        onClick={() => setDictationActive((v) => !v)}
      >
        {dictationActive ? "Stop dictation" : "Start dictation"}
      </button>
      {dictationActive && (
        <Dictation
          fieldId="clinical-notes"
          mode="in-field"
          initialText={notes}
          onSubmit={({ text }) => setNotes(text)}
          onCancel={() => setDictationActive(false)}
        />
      )}
    </DictationProvider>
  );
}
```

Your integration is working when turning dictation on shows the hosted UI, committed text updates **`notes`** through **`onSubmit`**, and **only one** **`<Dictation>`** is mounted at a time for that **`client`**.

## Best practices

<Tip>
  * **Reuse one dictation client.** Build a single **DictationClient** inside **`useMemo`** (or equivalent) for the page or shell. Creating a new client on every render breaks that pattern and often resets the hosted UI.

  * **Reuse one auth manager.** Create **SukiAuthManager** once inside the same **`useMemo`** as the client, as in the steps above.

  * **Handle when the user commits.** You must pass **`onSubmit`** so the SDK can deliver the final text. Without it, dictation often closes right after the user tries to finish.

  * **Pick a clear field label.** Each session needs a stable, unique **fieldId** in callbacks. Using the same value as the target input's **id** is a simple way to know which element to update. Refer to [Field IDs](/dictation-sdk/guides/configuration#field-ids-in-practice) guide for more details.

  * **Give the dictation host real height.** The node you use for **`rootElement`** (when you set it) should have height you control. Otherwise the dictation area can look blank. Refer to [Error handling](/dictation-sdk/guides/error-handling) and [In-field mode](/dictation-sdk/guides/in-field-mode) guides for more details.

  * **One active Dictation at a time.** Use boolean state or **`activeFieldId`** so you do not mount multiple dictation surfaces against the same **`client`** at once.

  * **Rely on unmount for hide.** Removing **`<Dictation>`** is the normal way to tear down the UI; you usually do not call **`hide()`** yourself in React.
</Tip>

## Next steps

Refer to the following guides for more information.

<Icon icon="file-lines" iconType="solid" /> [Configuration](/dictation-sdk/guides/configuration) to learn about the available options and how to use them.

<Icon icon="file-lines" iconType="solid" /> [JavaScript integration](/web-sdk/guides/dictation-javascript) to learn how to integrate audio dictation in a plain JavaScript application using the Suki Web SDK.
