ChatInput

PreviousNext

A controlled text input form for the chatbot, with a send button and optional audio/attachment trigger.

'use client';

import { useState } from 'react';
import { ChatInput } from '@/ui/ChatInput';

export function ChatInputDemo() {
  const [value, setValue] = useState('');

  return (
    <div className="w-[380px]">
      <ChatInput
        aria-label="Chat message input"
        value={value}
        onValueChange={setValue}
        onSubmit={() => setValue('')}
        onAudioClick={() => {}}
      />
    </div>
  );
}

Installation

npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/chat-input.json

Usage

import { ChatInput } from '@/ui/ChatInput';
import { useState } from 'react';
 
export function Component() {
  const [value, setValue] = useState('');
 
  return (
    <ChatInput
      value={value}
      onValueChange={setValue}
      onSubmit={() => {
        console.log('Submitted:', value);
        setValue('');
      }}
      onAudioClick={() => console.log('Audio clicked')}
    />
  );
}

Stop while an answer is generated

While isStreaming is true, submitting is disabled and the send button becomes a stop button that calls onStop. Set it when you start generating the answer, and reset it when the answer is complete or stopped.

'use client';

import { useRef, useState } from 'react';
import { ChatInput } from '@/ui/ChatInput';

export function ChatInputStreamingDemo() {
  const [value, setValue] = useState('');
  const [isStreaming, setIsStreaming] = useState(false);
  const timer = useRef<ReturnType<typeof setTimeout>>(undefined);

  function send() {
    setValue('');
    setIsStreaming(true);
    // Simulates an answer being generated for 4 seconds
    timer.current = setTimeout(() => setIsStreaming(false), 4000);
  }

  function stop() {
    clearTimeout(timer.current);
    setIsStreaming(false);
  }

  return (
    <div className="w-[380px]">
      <ChatInput
        aria-label="Chat message input"
        value={value}
        onValueChange={setValue}
        onSubmit={send}
        isStreaming={isStreaming}
        onStop={stop}
      />
    </div>
  );
}

Submit with Enter

By default Ctrl/Cmd + Enter submits and Enter adds a line break. Set submitKey="enter" for the usual chat behavior: Enter submits and Shift + Enter adds a line break (Ctrl/Cmd + Enter still submits).

'use client';

import { useState } from 'react';
import { ChatInput } from '@/ui/ChatInput';

export function ChatInputSubmitOnEnterDemo() {
  const [value, setValue] = useState('');

  return (
    <div className="w-[380px]">
      <ChatInput
        aria-label="Chat message input"
        value={value}
        onValueChange={setValue}
        onSubmit={() => setValue('')}
        submitKey="enter"
      />
    </div>
  );
}
submitKeyEnterShift + EnterCtrl/Cmd + Enter
"mod+enter" (default)line breakline breaksubmits
"enter"submitsline breaksubmits

The Enter that validates a text being composed with an IME (Japanese, Chinese…) never submits.

API Reference

ChatInput

PropTypeDefaultDescription
valuestring—Required. Controlled input value
onValueChange(value: string) => void—Required. Called on every keystroke
onSubmit() => void—Required. Called when the form is submitted
placeholderstring"Ask a question?"Input placeholder text (also used as aria-label)
submitKey"mod+enter" | "enter""mod+enter"Keyboard shortcut that submits the message, see Submit with Enter
isStreamingbooleanfalseWhile true, submitting is disabled and the send button becomes a stop button
onStop() => voidundefinedCalled when the stop button, shown while isStreaming, is clicked
onAudioClick() => voidundefinedEnables the microphone button. The browser speech recognition is used when available, this is the fallback otherwise
classNamestringundefinedAdditional CSS classes on the <form> element

Inherits all HTMLFormElement attributes.

Notes

  • The send button is disabled when the input is empty or whitespace only.
  • The microphone button, and the browser speech recognition behind it, are only enabled when onAudioClick is provided.
  • While isStreaming is true, neither the send button nor the keyboard shortcut submits.
  • The component is fully controlled — manage state externally.
  • Used as the bottom bar inside ChatWindow.