Skip to main content

Overview

This guide walks you through the process of integrating the Dictation SDK 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/dictation-react, @suki-sdk/dictation, and @suki-sdk/core.
  • Partner credentials: Obtain partnerId and partnerToken from Suki after 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 guide for more details.

Install the packages

Add all three packages to the same project you load in the browser:
pnpm add @suki-sdk/core @suki-sdk/dictation-react @suki-sdk/dictation 
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.

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 guide for recommended markup and CSS. Code example for container and field layout
React
<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. In order to create the Auth Manager, you must have the partnerId and partnerToken credentials from Suki. Refer to 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
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
React
import { useMemo } from "react";
import { SukiAuthManager } from "@suki-sdk/core";
import { DictationClient } from "@suki-sdk/dictation";

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
React
import { DictationProvider } from "@suki-sdk/dictation-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 guide for more details on the available options and how to use them. Code example for rendering Dictation in React
React
import { useState } from "react";
import { Dictation } from "@suki-sdk/dictation-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)}
        />
      )}
    </>
  );
}
You can also drive dictation with a single activeFieldId string and render one <Dictation> when it matches, which scales to multiple fields.
onSubmit is required for a good user experience. If you omit it, dictation often closes immediately after the user acts.

Callbacks

Props such as onSubmit, onCancel, and onDraft receive the same shape as in the JavaScript API:
React
{ fieldId: string, 
text: string 
}
Refer to Callbacks guide for more details on the available callbacks and how to use them.
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 guide for more details).

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.
React
import { useMemo, useState } from "react";
import { SukiAuthManager } from "@suki-sdk/core";
import { DictationClient } from "@suki-sdk/dictation";
import { DictationProvider, Dictation } from "@suki-sdk/dictation-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

  • 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 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 and 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.

Next steps

Refer to the following guides for more information.
Last modified on April 20, 2026