<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# ThreadRail

A thread beside its conversation: a labelled landmark with a header and a close button. Escape closes it. It takes focus when it opens and gives it back when it closes.

```tsx
import { ThreadRail } from "@/components/ouro/thread-rail/thread-rail";
```

## Example

```tsx
<ThreadRail label="Thread" title="Thread" detail="Design reviews" meta="2 replies" onClose={closeThread}>
  <MessageList label="Replies">{replies}</MessageList>
  <Composer label="Reply in thread" onSend={send} />
</ThreadRail>
```

## Use instead when

- Use Sheet instead when the thread should cover the page, as on a phone, and close on a tap outside it.

## Props

Type: `ThreadRailProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `autoFocus` | `boolean` | `true` | Whether the rail takes focus when it opens. Pass `false` to leave focus where it is. |
| `children` | `ReactNode` |  | The thread: usually a `MessageList` and a `Composer`, which fill the rail's height. |
| `className` | `string` |  | Layout only: the rail's size and margins. Appearance classes warn in development; the colors come from the theme. |
| `closeLabel` | `string` | `"Close thread"` | The close button's name, which its tooltip also shows. |
| `detail` | `string` |  | One muted line under the heading, cut short with an ellipsis: the conversation the thread belongs to. |
| `initialFocus` | `RefObject<HTMLElement \| null>` |  | The control that takes focus when the rail opens, instead of the rail itself. |
| `label` (required) | `string` |  | The rail's name for screen readers when `title` is left out, such as "Thread". Required, so the rail has a name. |
| `meta` | `ReactNode` |  | Muted words after the heading, such as "2 replies". |
| `onClose` (required) | `() => void` |  | Called when the close button is pressed, or Escape is pressed with focus in the rail. The app removes the rail in response. |
| `returnFocus` | `RefObject<HTMLElement \| null>` |  | Where focus goes when the rail closes, instead of the control that had focus when it opened. |
| `title` | `string` | the label | The heading's words, which screen readers also hear as the rail's name. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `onOpenChange`: Not a prop. The rail closes through `onClose`: `<ThreadRail onClose={() => setOpen(false)}>`.
- `open`: Not a prop. The rail shows while it is rendered: `{thread && <ThreadRail onClose={close}>}`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.
