javascripthtmlcssreactjscontenteditable

Struggling with Multi-Line Input Field for Combined User and AI Text


I’m working on an input field that combines user input (userText) and AI-generated suggestions (aiText). The goal is to make them appear as part of the same sentence, even when the user hasn’t accepted the AI’s suggestions yet.

input field

Currently, the input field is single-line, and when aiText is longer, it breaks awkwardly in the middle of the input field, making it look disjointed. Ideally, if aiText needs to wrap to a new line, it should start from the very left of the input component, not from the middle where userText ends.

Here’s the current implementation:

<div
  onClick={focusContentEditable}
  className="relative flex justify-start items-start p-3 border border-border
             bg-[#FFFFFF] text-[#1F1F1F] dark:bg-[#2A2A40] dark:text-[#EAEAEA] 
             focus-within:outline focus-within:outline-[#9462fd] 
             cursor-text rounded-2xl text-left w-full h-20 mx-auto 
             overflow-hidden"
>
  {/* Placeholder */}
  {userText.trim() === "" && !isFocused && (
    <span className="text-gray-400 text-xs">Ask me anything...</span>
  )}
  <div className="inline-flex items-baseline">
    <span
      ref={contentEditableRef}
      className="text-xs border-0 outline-none whitespace-nowrap break-words inline-flex min-h-[20px] w-full"
      contentEditable={true}
      suppressContentEditableWarning={true}
      onInput={handleInput}
      onKeyDown={handleKeyDown}
    >
      {/* {userText} */}
    </span>
    <span
      className={`text-xs text-gray-400 dark:text-gray-600 transition-opacity whitespace-normal inline-flex duration-500 ${
        aiText ? "opacity-100" : "opacity-0"
      }`}
      contentEditable={false}
    >
      {aiText.length > 0 && userText.trim() !== "" && <>{aiText}</>}
    </span>
  </div>
</div>

Problem:

  1. The input field is single-line, and I’m not enforcing line breaks.
  2. When aiText is present and long, it breaks mid-line, which disrupts the flow of the text.
  3. I want the input field to expand in height to accommodate a second line if needed, so aiText can wrap cleanly to the next line starting from the left edge.

What I’ve Tried:

Desired Behavior:

Any suggestions on how to achieve this? Thanks in advance!


Solution

  • I could definitely be missing something here, but I believe a <span contentEditable={false}> tag inside of a <p contentEditable={true}> tag should suffice to achieve your desired behavior.

    <p className="whitespace-pre-wrap" contentEditable={true}>
        This is some user input text
        <span contentEditable={false} className="text-xs text-gray-400">
            Here is some extremely looooooong looong looong looooong AI text
        </span>
    </p>
    

    We use the Tailwind class whitespace-pre-wrap to automatically wrap the aiText to the next line, should it overflow.