> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ChatInput

> A chat-style multi-line input with an integrated toolbar containing an optional file-attach button, optional right-side controls (e.g. a model selector), and a submit button — all inside a single bordered container.

```tsx theme={null}
import { ChatInput } from "@fanvue/ui";
import type {
  ChatInputAttachmentItem,
  ChatInputProps,
  ChatInputSelectOption,
} from "@fanvue/ui";
```

## Examples

## Default

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatinput--default&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="300" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatInput — Default" />
</Frame>

```tsx theme={null}
import { ChatInput } from "@fanvue/ui";

<ChatInput placeholder="Type a message..." />
```

## With Placeholder

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatinput--with-placeholder&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="300" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatInput — With Placeholder" />
</Frame>

```tsx theme={null}
import { ChatInput } from "@fanvue/ui";

<ChatInput placeholder="Ask the Creator Agent..." />
```

## With File Button

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatinput--with-file-button&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="300" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatInput — With File Button" />
</Frame>

```tsx theme={null}
import { ChatInput } from "@fanvue/ui";

<ChatInput placeholder="Type a message..." showFileButton />
```

## Full Feature

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatinput--full-feature&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="300" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatInput — Full Feature" />
</Frame>

```tsx theme={null}
import { useState } from "react";
import { AIIcon, BulbIcon, ChatInput } from "@fanvue/ui";

const SELECT_OPTIONS = [
  {
    value: "fanvue-ai",
    // Short label on the collapsed trigger; longer title inside the menu/sheet.
    label: "Fanvue AI",
    menuLabel: "Fanvue AI",
    description: "Most capable for ambitious work",
    icon: <AIIcon className="size-4" />,
  },
  {
    value: "example",
    label: "Example",
    menuLabel: "Example model",
    description: "Fastest for quick answers",
    icon: <BulbIcon className="size-4" />,
  },
];

function Example() {
  const [value, setValue] = useState("");
  const [model, setModel] = useState("fanvue-ai");
  const [fileHint, setFileHint] = useState<string | null>(null);

  return (
    <div className="flex w-full flex-col gap-2">
      <ChatInput
        placeholder="Ask the Creator Agent..."
        value={value}
        onChange={(e) => setValue(e.target.value)}
        onSubmit={() => setValue("")}
        showFileButton
        onFileClick={() => setFileHint("Attach tapped.")}
        selectOptions={SELECT_OPTIONS}
        selectValue={model}
        onSelectChange={setModel}
      />
      {fileHint ? (
        <output className="typography-description-12px-regular px-1 text-content-secondary">
          {fileHint}
        </output>
      ) : null}
    </div>
  );
}
```

## Disabled

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatinput--disabled&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="300" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatInput — Disabled" />
</Frame>

```tsx theme={null}
import { ChatInput } from "@fanvue/ui";

<ChatInput
  placeholder="Type a message..."
  disabled
  value="This input is disabled"
/>
```

## Props

## ChatInput

A chat-style multi-line input with an integrated toolbar containing an optional file-attach button, optional right-side controls (e.g. a model selector), and a submit button — all inside a single bordered container.

Designed to behave like modern AI chat inputs: auto-grows with content, submits on Enter (Shift+Enter for newlines), and keeps controls inline.

<ParamField path="attachmentPreviews" type="ReactNode">
  Replaces the built-in attachment strip entirely. When set to any value other than `undefined` (including `null` or `[]`), `ChatInputProps.attachments` is ignored.
</ParamField>

<ParamField path="attachments" type="ChatInputAttachmentItem[]">
  Image attachments shown in the built-in thumbnail strip. Ignored when `ChatInputProps.attachmentPreviews` is provided (including `null`).
</ParamField>

<ParamField path="className" type="string">
  Additional className applied to the outermost container.
</ParamField>

<ParamField path="fileButtonAriaLabel" type="string" default="Attach file">
  Accessible label for the attach-file button.
</ParamField>

<ParamField path="loading" type="boolean" default="false">
  Whether a submission is in progress (disables submit, shows visual feedback).
</ParamField>

<ParamField path="maxRows" type="number" default="6">
  Maximum number of visible rows before scrolling.
</ParamField>

<ParamField path="minRows" type="number" default="1">
  Minimum number of visible rows.
</ParamField>

<ParamField path="onAttachmentRemove" type="((id: string) => void)">
  Called when the user removes a built-in thumbnail. The remove button is disabled when this is omitted or the input is `ChatInputProps.disabled`.
</ParamField>

<ParamField path="onFileClick" type="(() => void)">
  Callback fired when the attach-file button is clicked. Only relevant when `showFileButton` is `true`.
</ParamField>

<ParamField path="onSelectChange" type="((value: string) => void)">
  Callback fired when the user picks a different dropdown option.
</ParamField>

<ParamField path="onSubmit" type="((value: string) => void)">
  Callback fired when the user submits (clicks the send button or presses Enter without Shift). Receives the current trimmed text value.
</ParamField>

<ParamField path="selectDisabled" type="boolean" default="false">
  When `true`, disables only the built-in dropdown selector.
</ParamField>

<ParamField path="selectMenuTitle" type="string" default="Select an option">
  Title shown at the top of the `"sheet"` variant of the built-in selector (e.g. "Switch AI Model").
</ParamField>

<ParamField path="selectOptions" type="ChatInputSelectOption[]">
  Options for the built-in inline dropdown selector (e.g. model picker). Ignored when `toolbarRight` is provided.
</ParamField>

<ParamField path="selectValue" type="string">
  Currently selected value for the built-in dropdown. Should match one of `selectOptions[].value`.
</ParamField>

<ParamField path="selectVariant" type="&#x22;menu&#x22; | &#x22;sheet&#x22;" default="menu">
  How the built-in selector presents its options:

  * `"menu"` (default) — a dropdown anchored to the trigger, for pointer/desktop.
  * `"sheet"` — a bottom sheet, for mobile/touch viewports.

  The viewport decision belongs to the consumer (it owns the breakpoint source of truth), so pass e.g. `selectVariant={isDesktop ? "menu" : "sheet"}`.
</ParamField>

<ParamField path="showFileButton" type="boolean" default="false">
  When `true`, renders an "attach file" button in the bottom-left toolbar.
</ParamField>

<ParamField path="submitAriaLabel" type="string" default="Send message">
  Accessible label for the submit button.
</ParamField>

<ParamField path="submitIcon" type="ReactNode" default="<ArrowUpIcon />">
  Icon element for the submit button.
</ParamField>

<ParamField path="toolbarRight" type="ReactNode">
  Optional content rendered in the bottom-right toolbar, to the left of the submit button. When provided, takes precedence over the built-in `selectOptions` dropdown.
</ParamField>

## Exported types

Also exported from `@fanvue/ui`: `ChatInputAttachmentItem`, `ChatInputProps`, `ChatInputSelectOption`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming)
