# Elements
URL: /docs/react-native/elements

The React Native elements, what each one installs, and what changes when the same design runs on a phone.

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

The React Native elements are the [elements](/elements) catalog rebuilt for Expo and React Native: the same names and visual language, and for the agent elements the same props, written against `@assistant-ui/react-native` and styled with [Uniwind](https://uniwind.dev) classes instead of DOM markup. They install the way shadcn components do, as source files in your project, so you can edit them once they land.

## What ships

Every element below is a registry item in the native tree at `https://r.assistant-ui.com/native/`. The CLI resolves that tree automatically when it finds `react-native` in your `package.json`.

| Element                                                          | Install as                  | Web twin                                       |
| ---------------------------------------------------------------- | --------------------------- | ---------------------------------------------- |
| Thread (composer, messages, action bars, branch picker)          | `thread`                    | [Thread](/elements/thread)                     |
| Thread list                                                      | `thread-list`               | [Thread list](/elements/thread-list)           |
| Attachments (composer previews, message attachments, add button) | `attachment`                | [Attachments](/elements/attachment)            |
| Markdown text                                                    | `markdown-text`             | [Markdown text](/elements/markdown-text)       |
| Typing indicator                                                 | `elements-typing-indicator` | [Typing indicator](/elements/typing-indicator) |
| Error state                                                      | `elements-error-state`      | [Error state](/elements/error-state)           |
| Stopped run                                                      | `elements-stopped-run`      | [Stopped run](/elements/stopped-run)           |
| Approval card                                                    | `elements-approval-card`    | [Approval card](/elements/approval-card)       |
| Agent status                                                     | `elements-agent-status`     | [Agent status](/elements/agent-status)         |
| Tool timeline                                                    | `elements-tool-timeline`    | [Tool timeline](/elements/tool-timeline)       |
| Icon button                                                      | `elements-icon-button`      | native only                                    |

The shared pieces come along as registry dependencies: `elements-surfaces` (the class recipes, the monospace style, the pulse and announcement hooks), `elements-range` (count normalization), `icon` (the Lucide wrapper) and `utils` (`cn`).

## Install

Add elements by name. The first install also needs the `components.json` from the [installation guide](/docs/react-native#add-the-elements), and every element expects Uniwind to be wired into Metro, because `className` on a React Native primitive does nothing without it.

```
npx assistant-ui@latest add elements-approval-card elements-agent-status
npx expo install --fix
```

Each element lands in `components/assistant-ui/elements/` next to the files it imports. The same items are reachable through shadcn directly when you want to pin the tree explicitly:

```
npx shadcn@latest add https://r.assistant-ui.com/native/elements-approval-card.json
```

The web catalog pages carry a React Native tab for every element that ships natively, with the element running inside a live Expo build and the install command above.

## Thread slots

The thread element exposes the parts a host most often replaces through a `components` prop. `Welcome`, `AssistantMessage` and `ToolFallback` mirror the web thread. `ComposerInput` is the React Native addition: it swaps the text input of both the new message composer and the edit composer, which is how a host with its own rich text editor keeps the attachments row and the send button.

```
import { useAui, useAuiState } from "@assistant-ui/react-native";
import { Thread } from "@/components/assistant-ui/elements/thread.aui";
import { RichEditor } from "@/components/rich-editor";

function ComposerInput() {
  const aui = useAui();
  const text = useAuiState((s) => s.composer.text);

  return (
    <RichEditor
      value={text}
      onChangeText={(next) => aui.composer.setText(next)}
      onSubmit={() => aui.composer.send()}
    />
  );
}

export default function ChatScreen() {
  return <Thread components={{ ComposerInput }} />;
}
```

## The agent elements

Approval card, agent status, tool timeline, stopped run and error state take plain props, so they render wherever your runtime puts the state. The usual home is a `ToolFallback` passed through the thread's `components`, where the tool call part carries `toolName`, `args`, `status` and, for server side approval gates, `approval` with `respondToApproval`.

```
import type { ToolCallMessagePartComponent } from "@assistant-ui/react-native";
import { AgentStatus } from "@/components/assistant-ui/elements/agent-status";
import { ApprovalCard } from "@/components/assistant-ui/elements/approval-card";

export const ToolUI: ToolCallMessagePartComponent = ({
  toolName,
  args,
  status,
  approval,
  respondToApproval,
}) => {
  if (approval && approval.approved === undefined) {
    return (
      <ApprovalCard
        state="request"
        title={`Run ${toolName}`}
        subtitle="Needs your approval"
        command={JSON.stringify(args)}
        onAllowOnce={() => respondToApproval({ approved: true })}
        onDeny={() => respondToApproval({ approved: false })}
      />
    );
  }

  return (
    <AgentStatus
      state={status.type === "running" ? "working" : "done"}
      label={toolName}
    />
  );
};
```

## On a phone

The elements keep the web design but a few things are decided differently on a device.

- **Touch targets.** Every pressable reaches 48dp. Icon buttons take `iconButtonHitSlop`, icon buttons that sit in a message footer row take `groupedIconButtonHitSlop` so neighbours do not overlap, and text buttons take `textButtonHitSlop`; all three are exported from `icon-button.tsx` and `surfaces.tsx` for your own controls.
- **Announcements.** `accessibilityLiveRegion` exists on Android and the web only, so state changes are announced through `useAnnounce` from `surfaces.tsx`, which calls `AccessibilityInfo.announceForAccessibility`. The approval card and the agent status announce changes, the error state and the typing indicator announce when they appear, and `webLiveRegion` adds the live region on the web build.
- **Reduce motion.** `useMotion` reads the OS setting once per screen and the pulse, shimmer and typing dots stay still when it is on. The looping animations run with `isInteraction: false`, so an indicator that never stops cannot block a list from rendering more rows.
- **Keyboard.** The thread measures where it sits in the window and passes that offset to `KeyboardAvoidingView`, so a navigation header above it does not hide the composer behind the keyboard.
- **Long histories.** `ThreadPrimitive.MessagesFlatList` keeps the visible message anchored while older ones load above it; the thread relies on that default.
- **Styling.** Tokens are the same `--color-*` variables as the web kit, declared under `@layer theme` with light and dark variants in your `global.css`; `dark:` classes and `active:` press states work as on the web. Web only classes are prefixed with `web:`.
- **Web export.** The same files run under react-native-web, which is how the [live showcase](https://assistant-ui-expo.vercel.app/showcase) and the catalog previews are built. Attributes that react-native-web does not map, such as `accessibilityState`, are written as their `aria-*` form.

## From web to React Native

| Web element                                                                            | React Native                                                        |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Thread, thread list, attachments, markdown text                                        | shipped                                                             |
| Typing indicator, error state, stopped run, approval card, agent status, tool timeline | shipped, same props                                                 |
| Reasoning, tool group, follow up suggestions, sources, file, image, conversation map   | not yet; build from the [primitives](/docs/react-native/primitives) |

The rest of the web catalog is DOM specific (hover, popovers, keyboard focus) and has no native plan.