ChatMessageEditor

PreviousNext

The in-place editor of a user message — edit the text, then cancel or send it again.

'use client';

import { useState } from 'react';
import { ChatMessageEditor } from '@/ui/chat/ChatMessageEditor';

export function ChatMessageEditorDemo() {
  const [message, setMessage] = useState('My son is 14 years old, what activities do you suggest?');
  const [isEditing, setIsEditing] = useState(true);

  return (
    <div className="w-[380px] flex flex-col items-end gap-8 px-20">
      {isEditing ? (
        <ChatMessageEditor
          value={message}
          onCancel={() => setIsEditing(false)}
          onSubmit={(content) => {
            setMessage(content);
            setIsEditing(false);
          }}
        />
      ) : (
        <>
          <p className="text-b3 bg-lightSand rounded-32 px-24 py-12 text-black">{message}</p>
          <button
            type="button"
            onClick={() => setIsEditing(true)}
            className="text-b4 font-semibold underline underline-offset-2"
          >
            Edit again
          </button>
        </>
      )}
    </div>
  );
}

Installation

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

Usage

ChatMessageEditor replaces the bubble of a user message while it is edited. ChatMessage already does it for you when you give it onEdit: use this component to build your own message bubble.

import { ChatMessageEditor } from '@/ui/chat/ChatMessageEditor';
import { useState } from 'react';
 
export function Component() {
  const [message, setMessage] = useState('My son is 14 years old.');
  const [isEditing, setIsEditing] = useState(true);
 
  return isEditing ? (
    <ChatMessageEditor
      value={message}
      onCancel={() => setIsEditing(false)}
      onSubmit={(content) => {
        setMessage(content);
        setIsEditing(false);
      }}
    />
  ) : (
    <p>{message}</p>
  );
}

Behavior

  • The textarea is focused on mount, with the caret at the end, and grows with its content.
  • Send is disabled while the text is empty or identical to value (ignoring the surrounding spaces), and onSubmit receives the trimmed text.
  • Esc cancels, Ctrl/Cmd + Enter sends. A plain Enter adds a line break.
  • Cancelling throws the draft away: the next edition starts again from value.

Translate the labels

<ChatMessageEditor
  value="Bonjour"
  labels={{ cancel: 'Annuler', send: 'Envoyer' }}
  onCancel={() => {}}
  onSubmit={() => {}}
/>

API Reference

ChatMessageEditor

PropTypeDefaultDescription
valuestring—Required. Initial text of the editor
onSubmit(value: string) => void—Required. Called with the trimmed text when it is sent
onCancel() => void—Required. Called when the edition is cancelled
labelsPartial<ChatMessageLabels>EnglishOnly cancel ("Cancel") and send ("Send") are used

See ChatMessageActions for the ChatMessageLabels type.

Notes

  • Only text can be edited: rich content (for instance rendered Markdown) cannot be put in a textarea.
  • The textarea is labelled "Edit message".