# AuiIf
URL: /docs/api-reference/primitives/assistant-if

Conditional rendering primitive for showing React UI from assistant-ui thread, message, composer, and runtime state.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

## Anatomy

```
import { AuiIf } from "@assistant-ui/react";

<AuiIf condition={(s) => s.thread.isEmpty}>
  <WelcomeScreen />
</AuiIf>;
```

## Overview

`AuiIf` is a generic conditional rendering component that provides access to the full assistant state. It replaces the deprecated `ThreadPrimitive.If`, `MessagePrimitive.If`, and `ComposerPrimitive.If` components with a single, flexible API.

## AssistantState

The condition function receives an `AssistantState` object with the following properties:

- `thread?`: `ThreadState` — The current thread state (always available).
- `message?`: `MessageState` — The current message state (available within a message context).
- `composer?`: `ComposerState` — The current composer state (always available).
- `part?`: `PartState` — The current message part state (available within a part context).
- `attachment?`: `AttachmentState` — The current attachment state (available within an attachment context).

## Examples

### Thread State Conditions

```
// Show welcome screen when thread is empty
<AuiIf condition={(s) => s.thread.isEmpty}>
  <WelcomeScreen />
</AuiIf>

// Show loading indicator while running
<AuiIf condition={(s) => s.thread.isRunning}>
  <LoadingSpinner />
</AuiIf>

// Conditional send/cancel button
<AuiIf condition={(s) => !s.thread.isRunning}>
  <ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
</AuiIf>
<AuiIf condition={(s) => s.thread.isRunning}>
  <ComposerPrimitive.Cancel>Cancel</ComposerPrimitive.Cancel>
</AuiIf>
```

### Message State Conditions

```
// Show avatar only for assistant messages
<AuiIf condition={(s) => s.message.role === "assistant"}>
  <AssistantAvatar />
</AuiIf>

// Show disclaimer on last message
<AuiIf condition={(s) => s.message.isLast}>
  <Disclaimer />
</AuiIf>

// Render content only after the assistant finishes streaming
<AuiIf condition={(s) =>
  s.message.role === "assistant" && s.message.status?.type === "complete"
}>
  <FollowUpCard />
</AuiIf>

// Toggle copy icon based on copied state
<ActionBarPrimitive.Copy>
  <AuiIf condition={(s) => !s.message.isCopied}>
    <CopyIcon />
  </AuiIf>
  <AuiIf condition={(s) => s.message.isCopied}>
    <CheckIcon />
  </AuiIf>
</ActionBarPrimitive.Copy>

// Show speak/stop button based on speech state
<AuiIf condition={(s) => s.message.speech == null}>
  <ActionBarPrimitive.Speak>
    <SpeakIcon />
  </ActionBarPrimitive.Speak>
</AuiIf>
<AuiIf condition={(s) => s.message.speech != null}>
  <ActionBarPrimitive.StopSpeaking>
    <StopIcon />
  </ActionBarPrimitive.StopSpeaking>
</AuiIf>
```

### Composer State Conditions

```
// Show placeholder when composer is empty
<AuiIf condition={(s) => s.composer.isEmpty}>
  <PlaceholderText />
</AuiIf>

// Show attachment preview when editing
<AuiIf condition={(s) => s.composer.isEditing}>
  <EditingIndicator />
</AuiIf>
```

### Complex Conditions

```
// Combine multiple conditions
<AuiIf condition={(s) =>
  !s.thread.isRunning && s.message.role === "assistant"
}>
  <ActionBar />
</AuiIf>

// Custom logic
<AuiIf condition={(s) =>
  s.thread.messages.length > 0 && !s.thread.isRunning
}>
  <FollowUpSuggestions />
</AuiIf>
```

## Type Export

You can import the `AuiIf.Condition` type for typing your condition functions:

```
import { AuiIf } from "@assistant-ui/react";

const isThreadEmpty: AuiIf.Condition = (s) => s.thread.isEmpty;

<AuiIf condition={isThreadEmpty}>
  <WelcomeScreen />
</AuiIf>;
```

## Migration from Deprecated Components

> [!warn]
>
> `ThreadPrimitive.If`, `MessagePrimitive.If`, and `ComposerPrimitive.If` are deprecated. Use `AuiIf` instead.

| Before                                 | After                                                       |
| -------------------------------------- | ----------------------------------------------------------- |
| `<ThreadPrimitive.If empty>`           | `<AuiIf condition={(s) => s.thread.isEmpty}>`               |
| `<ThreadPrimitive.If running>`         | `<AuiIf condition={(s) => s.thread.isRunning}>`             |
| `<ThreadPrimitive.If running={false}>` | `<AuiIf condition={(s) => !s.thread.isRunning}>`            |
| `<MessagePrimitive.If user>`           | `<AuiIf condition={(s) => s.message.role === "user"}>`      |
| `<MessagePrimitive.If assistant>`      | `<AuiIf condition={(s) => s.message.role === "assistant"}>` |
| `<MessagePrimitive.If copied>`         | `<AuiIf condition={(s) => s.message.isCopied}>`             |
| `<MessagePrimitive.If speaking>`       | `<AuiIf condition={(s) => s.message.speech != null}>`       |
| `<MessagePrimitive.If last>`           | `<AuiIf condition={(s) => s.message.isLast}>`               |
| `<ComposerPrimitive.If editing>`       | `<AuiIf condition={(s) => s.composer.isEditing}>`           |

## API Reference

### AuiIf

Conditionally renders children based on a slice of assistant state.

A thin wrapper around [useAuiState](/docs/api-reference/hooks/state#useauistate) that renders its children when `condition` returns `true` and unmounts them when it returns `false`. Keeps render logic declarative without mounting unused subtrees.

```
<AuiIf condition={(s) => s.thread.isRunning}>
  <CancelButton />
</AuiIf>
```

```
<AuiIf condition={(s) => s.thread.messages.length === 0}>
  <EmptyState />
</AuiIf>
```

- `condition`: `AuiIf.Condition` — Selector that decides whether to render \`children\`. Children render when this returns \`true\` and unmount when it returns \`false\`.