> ## 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.

# Form Filling Implementation In Web SDK For React

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

This guide shows how to integrate Form filling capabilities into a browser-based React application with the Suki Web SDK. You will create the **Auth Manager** and **Form filling Client** (typically inside **`useMemo`** so they are not recreated on every render), wrap your component tree with the **Form filling Provider**, and render **FormFilling** when the clinician should fill forms.

Use this approach if you are building with React and want to manage Form filling through components and hooks instead of imperative calls.

Let's get started!

## Prerequisites

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

* **Packages:** Install **`@suki-sdk/react`** and **`@suki-sdk/core`** (Web SDK **`v3.2.0`** or later).
* **Partner credentials:** Obtain **`partnerId`** and **`partnerToken`** from Suki after [Partner onboarding](/documentation/get-started/partner-onboarding).
* **Template IDs:** **`template_id`** UUIDs from your Suki support team for **`form_template_ids`**.
* **Encounter ID:** Pass your encounter ID as **`correlation_id`**. Refer to [Configuration](/form-filling-sdk/guides/configuration#correlation_id-your-encounter-id) for more details.
* **Browser and layout:** Your app runs in a **browser** over HTTPS, with microphone access and enough layout for the Form filling 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/react and @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. Import **`FormFillingClient`**, **`FormFillingProvider`**, **`FormFilling`**, and **`useFormFilling`** from **`@suki-sdk/react`**. You do not need **`@suki-sdk/form-filling-react`**.
</Tip>

## Step 1: Style the container

React renders the hosted UI inside **`.suki-form-filling`**. Give that container explicit height, or the iframe looks blank.

```css CSS theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
.suki-form-filling {
  width: 100%;
  height: min(80vh, 720px);
  min-height: 400px;
}
```

<Tip>
  Refer to [Configuration](/form-filling-sdk/guides/configuration#container-sizing) for recommended CSS.
</Tip>

## 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/get-started/partner-onboarding) guide to learn how to get these credentials.

In React you usually create the auth manager **inside** the same **`useMemo`** as the Form filling 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 Form filling client

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

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

**Code example for creating Form filling 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 { FormFillingClient } 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 FormFillingClient({
    authManager,
    onError: (err) => console.error(err.code, err.reason, err.message),
  });
}, []);
```

## Step 4: Wrap with FormFillingProvider

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

**Code example for wrapping with FormFillingProvider**

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

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

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

You can put **`FormFillingProvider`** at app root or only around the screen that needs Form filling.

## Step 5: Render FormFilling

Render **`<FormFilling>`** only while Form filling should be open (for example when the clinician clicked "Fill Forms with Suki"). When **`<FormFilling>`** unmounts, the SDK tears down the hosted UI for you.

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

**Code example for rendering FormFilling in React**

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

function EncounterFormFilling({ encounterId }) {
  const [isFormOpen, setIsFormOpen] = useState(false);

  const handleSubmit = (result) => {
    for (const form of result.structured_data.generated_values) {
      console.log(form.form_template_id, form.data);
    }
    setIsFormOpen(false);
  };

  return (
    <>
      <button
        type="button"
        onClick={() => setIsFormOpen(true)}
        disabled={isFormOpen}
      >
        Fill Forms with Suki
      </button>
      {isFormOpen && (
        <FormFilling
          form_template_ids={["YOUR_TEMPLATE_ID"]}
          correlation_id={encounterId}
          onReady={() => console.log("Ready")}
          onSubmit={handleSubmit}
          onCancel={() => setIsFormOpen(false)}
          onBackgroundSubmit={handleSubmit}
        />
      )}
    </>
  );
}
```

<Tip>
  You can also drive Form filling with a single **`isFormOpen`** boolean and mount one **`<FormFilling>`** when it is **`true`**, which scales cleanly across encounter screens.
</Tip>

<Note>
  **`onSubmit`** is required. It runs when structured JSON is ready after processing, not when the clinician taps submit in the hosted UI.
</Note>

## Callbacks

Props such as **`onReady`**, **`onSubmit`**, and **`onCancel`** mirror the JavaScript **`start()`** callbacks. **`onBackgroundSubmit`** is React-only (results for a superseded session while the iframe is still open). You can also listen with **`client.on()`** for handlers that stay active across many sessions:

```jsx React theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
client.on("form-filling:submitted", (result) => {
  console.log(result.ambient_session_id);
});
```

Refer to [Callbacks](/form-filling-sdk/guides/callbacks) for the **`FormFillingResult`** shape and [Events](/form-filling-sdk/api-reference/events) for every event and payload.

## useFormFilling hook

Inside **`FormFillingProvider`**, use **`useFormFilling()`** to read session state and errors in sibling components:

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

function FormFillingStatus() {
  const { isSessionActive, error } = useFormFilling();

  if (isSessionActive) {
    return <p>Form session active</p>;
  }
  if (error) {
    return (
      <p role="alert">
        Error ({error.code}): {error.message}
      </p>
    );
  }
  return null;
}
```

## Starting another session

Use the same **`client`** and **`FormFillingProvider`**. Mount **`<FormFilling>`** again (for example set **`isFormOpen`** back to **`true`**). You do **not** need a new **`FormFillingClient`**. Mount only one **`<FormFilling>`** at a time per **`client`**.

## Unmounting

When **`<FormFilling>`** unmounts, the SDK **automatically** tears down the hosted UI. You do not need to call **`stop()`** yourself for normal React flows.

## Complete code example

Below is a complete code example in React with **`FormFillingProvider`**, a launch button, and one Form filling session.

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

export function EncounterWithFormFilling({ encounterId }) {
  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 FormFillingClient({
      authManager,
      onError: (err) => console.error(err.code, err.message),
    });
  }, []);

  const [isFormOpen, setIsFormOpen] = useState(false);

  const handleSubmit = (result) => {
    for (const form of result.structured_data.generated_values) {
      console.log(form.form_template_id, form.data);
    }
    setIsFormOpen(false);
  };

  return (
    <FormFillingProvider client={client}>
      <h1>Encounter {encounterId}</h1>
      <button
        type="button"
        onClick={() => setIsFormOpen(true)}
        disabled={isFormOpen}
      >
        Fill Forms with Suki
      </button>
      {isFormOpen && (
        <FormFilling
          form_template_ids={["YOUR_TEMPLATE_ID"]}
          correlation_id={encounterId}
          onReady={() => console.log("Ready")}
          onSubmit={handleSubmit}
          onCancel={() => setIsFormOpen(false)}
          onBackgroundSubmit={handleSubmit}
        />
      )}
    </FormFillingProvider>
  );
}
```

Your integration is working when turning Form filling on shows the hosted UI, **`onSubmit`** returns **`structured_data`**, and **only one** **`<FormFilling>`** is mounted at a time for that **`client`**.

## Best practices

<Tip>
  * **Reuse one Form filling client.** Build a single **`FormFillingClient`** 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 structured results arrive.** You must pass **`onSubmit`** so the SDK can deliver **`structured_data`**. Map **`generated_values`** to your EHR or backend.

  * **Pass `correlation_id`.** Use your encounter ID so callbacks and Partner webhooks match the correct record.

  * **Use `onBackgroundSubmit`** when results arrive for a session the clinician has already replaced or reopened.

  * **One active FormFilling at a time.** Use boolean state so you do not mount multiple Form filling surfaces against the same **`client`** at once.

  * **Give the Form filling host real height.** Style **`.suki-form-filling`** with height you control. Otherwise the Form filling area can look blank.

  * **Rely on unmount for teardown.** Removing **`<FormFilling>`** is the normal way to close the UI; you usually do not call **`stop()`** yourself in React.
</Tip>

## Next steps

Refer to the following guides for more information.

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

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