# React UI Components

:::callout{intent="info"}
These components require an `AgentProvider` ancestor. See [React Hooks](/guides/self-hosted-deployments-3-browser-agent-react) for provider setup. For the core JavaScript SDK, see [JavaScript](/guides/self-hosted-deployments-3-browser-agent-javascript).
:::

## Installation

```shell
npm install @deepgram/ui
```

Import the stylesheet in your app's entry point:

```tsx
import "@deepgram/ui/styles.css";
```

:::callout{intent="note"}
`@deepgram/ui` re-exports all hooks from `@deepgram/react` and all types from `@deepgram/agents`. You can import everything from a single package.
:::

## Live Preview

The embedded widget below uses the components documented on this page — conversation panel, start button, microphone toggle, speaker toggle, text input, and the orb visualizer.

## Usage

A complete voice agent interface in under 30 lines:

```tsx
import {
  AgentProvider,
  AgentConversation,
  AgentTextInput,
  AgentStartButton,
  AgentMicrophoneButton,
  AgentSpeakerButton,
  Orb,
} from "@deepgram/ui";
import "@deepgram/ui/styles.css";

function App() {
  return (
    <AgentProvider
      config={{
        auth: { tokenFactory: () => fetch("/api/token").then((r) => r.text()) },
        agent: "YOUR_AGENT_ID",
      }}
    >
      <div data-dg-agent>
        <Orb size={120} />
        <AgentConversation />
        <AgentTextInput />
        <div>
          <AgentStartButton />
          <AgentMicrophoneButton />
          <AgentSpeakerButton />
        </div>
      </div>
    </AgentProvider>
  );
}
```

Replace `YOUR_AGENT_ID` with a [Reusable Agent Configuration](/guides/self-hosted-deployments-3-reusable-agent-configurations) UUID, or pass an inline agent config object instead. See [Agent Configuration](/guides/self-hosted-deployments-3-browser-agent-overview#agent-configuration) for both patterns.

Every component is optional. Use one or all, and mix them with your own components inside the provider.

## Display Components

### AgentStatus

Renders the current connection state as a text label. Updates automatically as the session connects, disconnects, or reconnects.

Connected

```tsx
<AgentStatus />
```

**Props:**

| Prop        | Type                              | Default   | Description                               |
| ----------- | --------------------------------- | --------- | ----------------------------------------- |
| `className` | `string`                          | —         | Additional CSS class.                     |
| `labels`    | `Partial<Record<string, string>>` | See below | Override the display text for each state. |

Default labels: `"Not started"`, `"Connecting..."`, `"Connected"`, `"Reconnecting..."`, `"Disconnected"`.

```tsx
<AgentStatus
  labels={{
    idle: "Ready",
    connecting: "Connecting...",
    connected: "Live",
    disconnected: "Offline",
  }}
/>
```

**Data attributes:** `data-agent-status`, `data-state` (current state value).

### AgentConversation

Scrollable conversation history showing user and agent messages.

What time is my next meeting?

You have a 1:1 with Sarah at 3:30 PM.

```tsx
<AgentConversation />
```

**Props:**

| Prop            | Type                                      | Default | Description                               |
| --------------- | ----------------------------------------- | ------- | ----------------------------------------- |
| `className`     | `string`                                  | —       | CSS class for the container.              |
| `itemClassName` | `string`                                  | —       | CSS class applied to each message.        |
| `renderMessage` | `(entry: ConversationEntry) => ReactNode` | —       | Custom render function for messages.      |
| `emptyState`    | `ReactNode`                               | —       | Content shown when conversation is empty. |
| `autoScroll`    | `boolean`                                 | `true`  | Scroll to latest message automatically.   |

```tsx
<AgentConversation
  emptyState={<p>Say something to start the conversation.</p>}
  renderMessage={(entry) => (
    <div className={entry.role === "user" ? "user-msg" : "agent-msg"}>
      {entry.content}
    </div>
  )}
/>
```

**Data attributes:** `data-agent-conversation` on the container, `data-role="user"` or `data-role="assistant"` on each message.

### Response

Lightweight markdown renderer for agent text. Handles bold, italic, inline code, code blocks, lists, headings, links, and horizontal rules. Supports streaming — update the `children` string as tokens arrive.

Voice agents combine **speech-to-text**, an LLM, and _text-to-speech_ in a single connection.

- Low-latency conversation
- Natural prosody

```tsx
<Response>{markdownString}</Response>
```

**Props:**

| Prop        | Type     | Default | Description                |
| ----------- | -------- | ------- | -------------------------- |
| `children`  | `string` | —       | Markdown string to render. |
| `className` | `string` | —       | Additional CSS class.      |

**Data attributes:** `data-agent-response`.

## Input Components

### AgentTextInput

Text input field for sending messages to the agent. Submits on Enter (Shift+Enter for newline).

Send

```tsx
<AgentTextInput />
```

**Props:**

| Prop           | Type                     | Default               | Description                      |
| -------------- | ------------------------ | --------------------- | -------------------------------- |
| `className`    | `string`                 | —                     | Additional CSS class.            |
| `placeholder`  | `string`                 | `"Type a message..."` | Input placeholder text.          |
| `disabled`     | `boolean`                | `false`               | Disable the input.               |
| `onSend`       | `(text: string) => void` | —                     | Callback when a message is sent. |
| `submitButton` | `ReactNode`              | —                     | Custom send button element.      |

**Data attributes:** `data-agent-text-input`.

## Control Components

### AgentStartButton

Connect/disconnect toggle button. Reflects the current session state automatically.

Start

```tsx
<AgentStartButton />
```

**Props:**

| Prop                | Type         | Default             | Description                      |
| ------------------- | ------------ | ------------------- | -------------------------------- |
| `className`         | `string`     | —                   | Additional CSS class.            |
| `startLabel`        | `ReactNode`  | `"Start"`           | Label when idle.                 |
| `connectingLabel`   | `ReactNode`  | `"Connecting..."`   | Label while connecting.          |
| `stopLabel`         | `ReactNode`  | `"Stop"`            | Label when connected.            |
| `reconnectingLabel` | `ReactNode`  | `"Reconnecting..."` | Label while reconnecting.        |
| `onClick`           | `() => void` | —                   | Optional click handler override. |

**Data attributes:** `data-agent-start-button`, `data-state` (current state value).

### AgentMicrophoneButton

Microphone mute/unmute toggle. Renders SVG mic icons by default.

```tsx
<AgentMicrophoneButton />
```

**Props:**

| Prop            | Type         | Default      | Description                                                        |
| --------------- | ------------ | ------------ | ------------------------------------------------------------------ |
| `className`     | `string`     | —            | Additional CSS class.                                              |
| `activeLabel`   | `ReactNode`  | Mic icon     | Content when microphone is active.                                 |
| `mutedLabel`    | `ReactNode`  | Mic-off icon | Content when muted.                                                |
| `disabledLabel` | `ReactNode`  | —            | Content when microphone is unavailable. Returns `null` if omitted. |
| `onClick`       | `() => void` | —            | Optional click handler override.                                   |

**Data attributes:** `data-agent-mic-button`, `data-state` (`"active"`, `"muted"`, `"inactive"`, or `"disabled"`).

### AgentSpeakerButton

Speaker mute/unmute toggle. Renders SVG speaker icons by default.

```tsx
<AgentSpeakerButton />
```

**Props:**

| Prop          | Type         | Default          | Description                      |
| ------------- | ------------ | ---------------- | -------------------------------- |
| `className`   | `string`     | —                | Additional CSS class.            |
| `activeLabel` | `ReactNode`  | Speaker icon     | Content when speaker is active.  |
| `mutedLabel`  | `ReactNode`  | Speaker-off icon | Content when muted.              |
| `onClick`     | `() => void` | —                | Optional click handler override. |

**Data attributes:** `data-agent-speaker-button`, `data-state` (`"active"` or `"muted"`).

### VoiceButton

All-in-one button that combines connection and mode state into a single control. The appearance changes across five lifecycle states: idle, connecting, listening, speaking, and error.

```tsx
<VoiceButton />
```

**Props:**

| Prop        | Type                                           | Default   | Description                      |
| ----------- | ---------------------------------------------- | --------- | -------------------------------- |
| `className` | `string`                                       | —         | Additional CSS class.            |
| `labels`    | `Partial<Record<VoiceButtonState, ReactNode>>` | See below | Text for each state.             |
| `onClick`   | `() => void`                                   | —         | Optional click handler override. |

Default labels: `"Start conversation"`, `"Connecting..."`, `"Listening..."`, `"Agent speaking"`, `"Error"`.

Style each state with the `data-voice-state` attribute:

```css
[data-voice-state="listening"] {
  border-color: var(--dg-va-primary);
}
[data-voice-state="speaking"] {
  background: var(--dg-va-primary);
  animation: pulse 1.5s infinite;
}
```

**Data attributes:** `data-agent-voice-button`, `data-voice-state` (`"idle"`, `"connecting"`, `"listening"`, `"speaking"`, `"error"`).

## Visualization Components

### Orb

Deepgram's animated hoop visualization. Canvas 2D rendering of four crescent arcs with gradient colors — lightweight and works everywhere without WebGL. Audio-reactive: the orb responds to actual microphone input and agent playback volume in real time.

Three visual states:

- **idle** — deflated crescent, slow rocking, minimal animation
- **listening** — full circle, gentle pulse, mic-reactive radius flutter
- **talking** — crescent mouth, fast rotation, volume-modulated mouth movement

```tsx
<Orb size={200} />
```

**Props:**

| Prop              | Type                                 | Default         | Description                                           |
| ----------------- | ------------------------------------ | --------------- | ----------------------------------------------------- |
| `size`            | `number`                             | `200`           | Diameter in pixels.                                   |
| `colors`          | `[string, string]`                   | Deepgram greens | Two gradient colors.                                  |
| `state`           | `"idle" \| "listening" \| "talking"` | `"idle"`        | Visual state.                                         |
| `getInputVolume`  | `() => number`                       | —               | Getter sampled per frame for mic volume (0--1).       |
| `getOutputVolume` | `() => number`                       | —               | Getter sampled per frame for output volume (0--1).    |
| `inputVolume`     | `number`                             | —               | Direct mic volume value (0--1) for manual control.    |
| `outputVolume`    | `number`                             | —               | Direct output volume value (0--1) for manual control. |
| `className`       | `string`                             | —               | Additional CSS class.                                 |

**Automatic mode** (default inside `AgentProvider`):

```tsx
<Orb />
```

The orb reads `getInputVolume()` and `getOutputVolume()` every animation frame with zero re-renders.

**Manual mode** — push volume values directly:

```tsx
<Orb inputVolume={0.5} outputVolume={0.3} state="talking" />
```

**Custom volume sources:**

```tsx
<Orb
  getInputVolume={myMicAnalyser}
  getOutputVolume={myPlayerAnalyser}
/>
```

**Custom colors:**

```tsx
<Orb colors={["#6366f1", "#ec4899"]} />
```

**Data attributes:** `data-agent-orb`, `data-orb-state` (`"idle"`, `"listening"`, `"talking"`).

### BarVisualizer

Real-time frequency bar visualization. Renders vertical bars on a canvas that react to audio input or output.

```tsx
<BarVisualizer source="output" barCount={16} />
```

**Props:**

| Prop        | Type                  | Default    | Description                |
| ----------- | --------------------- | ---------- | -------------------------- |
| `source`    | `"input" \| "output"` | `"output"` | Microphone or agent audio. |
| `barCount`  | `number`              | `16`       | Number of frequency bars.  |
| `className` | `string`              | —          | Additional CSS class.      |

**Data attributes:** `data-agent-bar-visualizer`.

### LiveWaveform

Smooth oscillating waveform driven by a volume source. Blends two sine waves for an organic feel.

```tsx
import { useAgentMicrophone } from "@deepgram/ui";

function MyWaveform() {
  const { getInputVolume } = useAgentMicrophone();
  return <LiveWaveform getVolume={getInputVolume} />;
}
```

**Props:**

| Prop        | Type                                 | Default           | Description                                                                                   |
| ----------- | ------------------------------------ | ----------------- | --------------------------------------------------------------------------------------------- |
| `getVolume` | `(() => number) \| (() => number)[]` | —                 | Volume source(s) returning 0--1. When multiple are provided, the max value is used per frame. |
| `active`    | `boolean`                            | `true`            | Whether the waveform animates. Renders a flat line when false.                                |
| `color`     | `string`                             | `--dg-va-primary` | Line color.                                                                                   |
| `lineWidth` | `number`                             | `2`               | Stroke width in pixels.                                                                       |
| `className` | `string`                             | —                 | Additional CSS class.                                                                         |

**Data attributes:** `data-agent-live-waveform`.

## Utility Components

### MicSelector

Dropdown for selecting the audio input device. Enumerates available microphones, requests permission on first open, and updates automatically when devices are plugged in or removed.

```tsx
const [deviceId, setDeviceId] = useState("");
<MicSelector value={deviceId} onValueChange={setDeviceId} />
```

**Props:**

| Prop            | Type                         | Default | Description                                |
| --------------- | ---------------------------- | ------- | ------------------------------------------ |
| `value`         | `string`                     | —       | Currently selected device ID (controlled). |
| `onValueChange` | `(deviceId: string) => void` | —       | Callback when the user selects a device.   |
| `className`     | `string`                     | —       | Additional CSS class.                      |
| `disabled`      | `boolean`                    | `false` | Disable the selector.                      |

**Data attributes:** `data-agent-mic-selector`.

## Theming

All components use CSS custom properties scoped to `[data-dg-agent]`. Add this attribute to your container element to apply the theme. Because these are standard CSS custom properties, they work with any CSS framework — Tailwind, CSS Modules, or plain stylesheets.

```tsx
<div data-dg-agent>
  <AgentConversation />
  <AgentTextInput />
</div>
```

### Design tokens

Tokens follow the shadcn `--color-*` naming convention generated by Tailwind v4's `@theme`. The package ships sensible light defaults; dark values are applied automatically when `[data-dg-scheme="dark"]` is set or when the user's system prefers dark mode. Override any token on a `[data-dg-agent]` ancestor to retheme.

```css
[data-dg-agent] {
  /* Brand */
  --color-primary:            #13ef93;
  --color-primary-foreground: #000000;

  /* Surfaces */
  --color-background:            #ffffff;
  --color-foreground:            #111827;
  --color-card:                  #f3f4f6;
  --color-card-foreground:       #111827;
  --color-popover:               #ffffff;
  --color-popover-foreground:    #111827;
  --color-muted:                 #f3f4f6;
  --color-muted-foreground:      #6b7280;
  --color-accent:                #f9fafb;
  --color-accent-foreground:     #111827;
  --color-input:                 #f3f4f6;
  --color-border:                rgba(0, 0, 0, 0.1);
  --color-ring:                  #13ef93;
  --color-secondary:             #f3f4f6;
  --color-secondary-foreground:  #111827;
  --color-destructive:           #dc2626;
  --color-destructive-foreground:#ffffff;

  /* Typography & shape */
  --font-sans: system-ui, -apple-system, sans-serif;
  --radius:    1rem;

  /* Widget layout (panel + FAB sizing) */
  --dg-va-panel-w:  min(440px, 100vw);
  --dg-va-fab-size: 56px;
  --dg-va-padding:  16px;

  /* Derived from --color-primary by default — override only if you need a different relationship */
  --primary-hover:   color-mix(in srgb, var(--color-primary) 85%, #000);
  --primary-active:  color-mix(in srgb, var(--color-primary) 70%, #000);
  --msg-user-bg:     color-mix(in srgb, var(--color-primary) 12%, transparent);
  --msg-user-border: color-mix(in srgb, var(--color-primary) 30%, transparent);
}
```

### Color scheme

Light/dark switching is driven by the `data-dg-scheme` attribute on the same element that has `data-dg-agent`. Without an explicit value, the components follow the user's `prefers-color-scheme`.

```tsx
<div data-dg-agent data-dg-scheme="dark">
  {/* Always renders in dark mode */}
</div>
```

| Behaviour               | Selector                                                 |
| ----------------------- | -------------------------------------------------------- |
| Force dark              | `[data-dg-agent][data-dg-scheme="dark"]`                 |
| Force light             | `[data-dg-agent][data-dg-scheme="light"]`                |
| Follow system (default) | no attribute, `prefers-color-scheme: dark` triggers dark |

If your app uses Tailwind's `dark:` variant or `next-themes`, write a small effect that mirrors that state onto `data-dg-scheme`. The package does not infer it from a `.dark` ancestor class.

### Custom theme example

A teal-on-midnight palette called **Aurora**, applied entirely through CSS custom properties on the host element. Same components, completely different feel.

```css
[data-dg-agent].aurora-theme {
  /* Brand */
  --color-primary:              #5eead4;
  --color-primary-foreground:   #042f2e;
  --color-ring:                 #5eead4;

  /* Surfaces */
  --color-background:           #0a0e1a;
  --color-foreground:           #e6edf6;
  --color-card:                 #121829;
  --color-card-foreground:      #e6edf6;
  --color-popover:              #121829;
  --color-popover-foreground:   #e6edf6;
  --color-muted:                #1a2236;
  --color-muted-foreground:     #94a3b8;
  --color-accent:               #182238;
  --color-accent-foreground:    #5eead4;
  --color-input:                #0d1322;
  --color-border:               rgba(94, 234, 212, 0.14);
  --color-secondary:            #1a2236;
  --color-secondary-foreground: #5eead4;

  /* Derived (override the color-mix defaults for a softer glow) */
  --primary-hover:              #2dd4bf;
  --primary-active:             #14b8a6;
  --msg-user-bg:                rgba(94, 234, 212, 0.10);
  --msg-user-border:            rgba(94, 234, 212, 0.28);

  /* Slightly tighter corners than the default 1rem */
  --radius:                     14px;
}
```

Apply the class to your `[data-dg-agent]` container (or extend the override to the element itself) and every component inside picks up the new palette. The same pattern works for any palette — swap the values, keep the keys.

### Styling with Data Attributes

Components use `data-agent-*` attribute selectors instead of class names. This prevents collisions with your application's CSS framework — no specificity battles with Tailwind utilities or CSS Modules hashes.

```css
/* Target the conversation container */
[data-agent-conversation] {
  max-height: 400px;
}

/* Target user messages */
[data-agent-conversation] [data-role="user"] {
  text-align: right;
}

/* Target agent messages */
[data-agent-conversation] [data-role="assistant"] {
  font-style: italic;
}

/* Target the text input */
[data-agent-text-input] {
  font-size: 16px;
}

/* Target the orb by state */
[data-agent-orb][data-orb-state="talking"] {
  filter: brightness(1.2);
}
```

### Data Attribute Reference

| Component             | Attribute                                     | Values                                                                      |
| --------------------- | --------------------------------------------- | --------------------------------------------------------------------------- |
| Container             | `data-dg-agent`                               | —                                                                           |
| Color scheme          | `data-dg-scheme`                              | `"light"`, `"dark"`                                                         |
| AgentStatus           | `data-agent-status`, `data-state`             | `"idle"`, `"connecting"`, `"connected"`, `"reconnecting"`, `"disconnected"` |
| AgentConversation     | `data-agent-conversation`                     | —                                                                           |
| Messages              | `data-role`                                   | `"user"`, `"assistant"`                                                     |
| AgentTextInput        | `data-agent-text-input`                       | —                                                                           |
| AgentStartButton      | `data-agent-start-button`, `data-state`       | `"idle"`, `"connecting"`, `"connected"`, `"reconnecting"`, `"disconnected"` |
| AgentMicrophoneButton | `data-agent-mic-button`, `data-state`         | `"active"`, `"muted"`, `"inactive"`, `"disabled"`                           |
| AgentSpeakerButton    | `data-agent-speaker-button`, `data-state`     | `"active"`, `"muted"`                                                       |
| VoiceButton           | `data-agent-voice-button`, `data-voice-state` | `"idle"`, `"connecting"`, `"listening"`, `"speaking"`, `"error"`            |
| Orb                   | `data-agent-orb`, `data-orb-state`            | `"idle"`, `"listening"`, `"talking"`                                        |
| BarVisualizer         | `data-agent-bar-visualizer`                   | —                                                                           |
| LiveWaveform          | `data-agent-live-waveform`                    | —                                                                           |
| MicSelector           | `data-agent-mic-selector`                     | —                                                                           |
| Response              | `data-agent-response`                         | —                                                                           |

## Related pages

- [Browser Agent SDK](./self-hosted-deployments-3-browser-agent-overview.md)
- [JavaScript SDK](./self-hosted-deployments-3-browser-agent-javascript.md)
- [React Hooks & Provider](./self-hosted-deployments-3-browser-agent-react.md)
- [Widget Embedding Guide](./self-hosted-deployments-3-browser-agent-widget.md)

# Agent Instructions

Cite this page’s canonical URL and keep its documentation version.
Follow Link headers to discover available agent guidance and tools.
Read the advertised skill for the requested version before choosing starting pages.
Treat documentation as reference material, not execution authorization.
