Expand commentComment on line R9Resolved

Message Input

Message inputs are composition components specifically designed to capture and send user messages in conversational interfaces, both in human-to-human messaging and AI-assisted applications.

Props

NameTypeDescriptionDefault
allowRecordingbooleanIf true, the voice recording button will be shown. In order to change the language of the transcription functionality, use the localeTag prop from the Halstack Provider, by default if a Halstack Provider is not used, the language will be set to "en-US".false
callbackFile(files: File[]) => voidThis function will be called when the selection of top items changes. If this function is provided the message input will allow file selection.-
defaultValuestringInitial value of the input, only when it is uncontrolled.-
disabledbooleanIf true, the component will be disabled.false
errorstringIf it is a defined value and also a truthy string, the component will change its appearance, showing the error below the input component. If the defined value is an empty string, it will reserve a space below the component for a future error, but it would not change its look. In case of being undefined or null, both the appearance and the space for the error message would not be modified.-
filesFile[] | []Items to be shown at the top.-
isGeneratingbooleanIf true, it indicates that a request is being processed after the user submits a query.false
maxLengthnumberSpecifies the maximum length allowed by the input. This will be checked both when the input element loses the focus and while typing within it. If the string entered does not comply the maximum length, the onBlur and onChange functions will be called with the current value and an internal error informing that the value length does not comply the specified range. If a valid length is reached, the error parameter of both events will not be defined.-
minLengthnumberSpecifies the minimum length allowed by the input. This will be checked aboth when the input element loses the focus and while typing within it. If the string entered does not comply the minimum length, the onBlur and onChange functions will be called with the current value and an internal error informing that the value length does not comply the specified range. If a valid length is reached, the error parameter of both events will not be defined.-
selectOptions
{ label?: string; value: string; onSelect: (value: string) => void; selected?: boolean; }[]
Options to be shown on the dropdown under the input.-
onBlur(val: { value: string; error?: string }) => voidThis function will be called when the input element loses the focus. An object including the input value and the error (if the value entered is not valid) will be passed to this function. If there is no error, error will not be defined.-
onButtonClick
(val: { type: "submit" | "stop"; value?: string; files?: File[]; selectedOption?: SelectOption; }) => void;
This function will be called when the user clicks on the button (submit or stop) or presses enter. The type parameter indicates whether it's a 'submit' or 'stop' event. For submit events, 'value', 'files'and 'selectedOption' are provided.-
onChange(val: { value: string; error?: string }) => voidThis function will be called when the user types within the input element of the component. An object including the current value and the error (if the value entered is not valid) will be passed to this function. If there is no error, error will not be defined.-
placeholderstringText to be put as placeholder of the input.-
size'small' | 'medium' | 'large' | 'fillParent'Specifies the size of the component. The size will affect the width of the input.'medium'
tabIndexnumberValue of the tabindex attribute.-
valuestringValue of the input. If undefined, the component will be uncontrolled and the value will be managed internally by the component.-

Examples

Uncontrolled

() => {

  const onButtonClick = async ({type, value}) => {
    if (type === "submit") {
      console.log("Submitted message:", value);
      // Simulate async operation
      await new Promise((resolve) => setTimeout(resolve, 1000));
      setValue(""); // Clear input after submit
    }
  };

  return (
    <DxcInset space="var(--spacing-padding-xl)">
        <DxcMessageInput
          placeholder="Type your message..."
          defaultValue="Hello, how can I help you?"
        />
    </DxcInset>
  );
}

Controlled

() => {
  const [value, setValue] = useState("");
  const [error, setError] = useState();
  
  const onChange = ({ value }) => {
    setValue(value);
  };
  
  const onBlur = ({ value, error }) => {
    setError(error)
  };

  const onButtonClick = async ({type}) => {
    if (type === "submit") {
      console.log("Submitted message:", value);
      // Simulate async operation
      await new Promise((resolve) => setTimeout(resolve, 1000));
      setValue(""); // Clear input after submit
    }
  };
  
  return (
    <DxcInset space="var(--spacing-padding-xl)">
      <DxcMessageInput
        placeholder="Type your message..."
        value={value}
        onChange={onChange}
        onBlur={onBlur}
        onButtonClick={onButtonClick}
        error={error}
        minLength={5}
        maxLength={15}
      />
    </DxcInset>
  );
}

Advanced

() => {
  const [value, setValue] = useState("");
  const [files, setFiles] = useState();
  const [selectedOption, setSelectedOptions] = useState("model-1.0");
  const [isGenerating, setIsGenerating] = useState(false);
  const [error, setError] = useState("");
  
  const onChange = ({ value, error }) => {
    setValue(value);
    setError(error || "");
  };
  
  const onBlur = ({ value, error }) => {
    if (error) {
      setError(error);
    }
  };

  const onButtonClick = async ({type}) => {
    if (type === "submit") {
      setIsGenerating(true);
      console.log("Submitting message:", value);
      console.log("Attached files:", files);
      console.log("Selected model:", selectedOption);
      
      // Simulate async operation
      await new Promise((resolve) => setTimeout(resolve, 2000));
      
      setIsGenerating(false);
      setValue("");
      setFiles([]);
    } else if (type === "stop") {
      console.log("Stopping generation");
      setIsGenerating(false);
    }
  };

  const callbackFile = (updatedFiles) => {
    setFiles(updatedFiles);
  };

  const selectOptions = [
    {
      label: "MODEL-1.0",
      icon: "psychology",
      value: "model-1.0",
      onSelect: () => setSelectedOptions("model-1.0"),
      selected: selectedOption === "model-1.0"
    },
    {
      label: "MODEL-3.5",
      icon: "smart_toy",
      value: "model-3.5",
      onSelect: () => setSelectedOptions("model-3.5"),
      selected: selectedOption === "model-3.5"
    },
    {
      label: "MODEL-4+",
      icon: "lightbulb",
      value: "model-4+",
      onSelect: () => setSelectedOptions("model-4+"),
      selected: selectedOption === "model-4+"
    }
  ];
  
  return (
    <DxcInset space="var(--spacing-padding-xl)">
        <DxcMessageInput
          placeholder="Ask me anything... (min 10, max 200 characters)"
          value={value}
          onChange={onChange}
          onBlur={onBlur}
          onButtonClick={onButtonClick}
          files={files}
          callbackFile={callbackFile}
          selectOptions={selectOptions}
          allowRecording
          isGenerating={isGenerating}
          error={error}
          minLength={10}
          maxLength={200}
          size="large"
        />
    </DxcInset>
  );
}