For AI agents: the complete documentation index is available at /ooui-react/en/llms.txt, the full documentation bundle is available at /ooui-react/en/llms-full.txt, and this page is available as Markdown at /ooui-react/en/components/multiline-text-input/index.md.
  • English
  • MultilineTextInput

    Source | Original component

    A multi-line text input; input capabilities match TextInput.

    Basic usage

    Current length: 0
    import { useState } from "react";
    import { MultilineTextInput } from "ooui-react";
    
    function App() {
      const [text, setText] = useState("");
    
      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 12, maxWidth: 320 }}>
          <MultilineTextInput value={text} onChange={setText} placeholder="Controlled multiline input" />
          <div>Current length: {text.length}</div>
          <MultilineTextInput defaultValue="Uncontrolled; the component remembers what you type" />
        </div>
      );
    }
    
    export default App;

    Rows and auto height

    rows is the minimum number of rows (written to the <textarea>'s rows attribute). With autosize on, the height follows the content: it grows until maxRows and turns into internal scrolling beyond that; maxRows defaults to max(2 × rows, 10).

    Without autosize, the height stays at rows lines and overflowing content scrolls.

    Beyond input, the auto-height re-measure has a size-observer fallback: font loading and container or width changes also trigger a re-measure (the original only re-measures on input, so the height can lag behind).

    import { MultilineTextInput } from "ooui-react";
    
    function App() {
      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 12, maxWidth: 320 }}>
          <MultilineTextInput autosize rows={2} placeholder="autosize: grows with the content" />
          <MultilineTextInput rows={3} defaultValue={"Line one\nLine two\nLine three\nLine four\nLine five"} />
        </div>
      );
    }
    
    export default App;

    Scrollbar offset

    When a vertical scrollbar appears, the indicator and the label placed after the input shift by the scrollbar width to stay clear of it (always enabled for multiline input; nothing to configure). When the input's direction diverges from the page's (e.g. a dir='rtl' input on an LTR page), the offset is withdrawn entirely, avoiding the label-stretching distortion the original shows in that case.

    Line breaks and Enter

    Enter always inserts a line break.

    Differences from OOUI

    The original's allowLinebreaks option (suppressing line breaks and cleaning them into spaces) and its companion enter event (fired on Ctrl/Cmd+Enter) are not provided here — to restrict line breaks, clean the value in onChange.

    Capabilities shared with TextInput

    The following behave exactly as in TextInput and are not repeated here:

    • Label: label / labelPosition / invisibleLabel;
    • Icon and indicator: icon, indicator; when indicator is not given explicitly and required is true, it falls back to the required indicator;
    • Soft validation: validate (RegExp / function / 'non-empty' / 'integer'), flags without rewriting the value;
    • State: maxLength, readOnly (focusable and copyable), disabled.
    Bio
    import { MultilineTextInput } from "ooui-react";
    
    function App() {
      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 12, maxWidth: 320 }}>
          <MultilineTextInput label="Bio" labelPosition="before" placeholder="Up to 20 characters" maxLength={20} />
          <MultilineTextInput validate="non-empty" placeholder="Clear it and blur to see it flagged" />
        </div>
      );
    }
    
    export default App;

    Where props land

    The component root is a non-focusable <div> and the input element is a <textarea>. The landing rules are the same as TextInput:

    • ...rest from props lands on the root div; attributes that must go on the native <textarea> (such as role, aria-*) go through the inputProps channel, whose onChange/onBlur/onFocus are chained after the component's own logic.
    • inputRef points to the inner <textarea> (the component ref points to the root div); use inputRef to focus the input.
    • tabIndex, title, dir, accessKey and name are taken over by the component and land directly on the <textarea> (matching the original's landing spots), not via rest.

    API

    PropDescriptionTypeDefault
    valueInput value (controlled; passing it enables controlled mode)string—
    defaultValueUncontrolled initial valuestring—
    onChangeValue-change handler (value-first, includes the native event)ChangeHandler<string, HTMLTextAreaElement>—
    rowsMinimum number of rowsnumber—
    maxRowsHeight cap for autosize, in rowsnumbermax(2 × rows, 10)
    autosizeWhether the height follows the contentbooleanfalse
    placeholderInput hintstring—
    maxLengthMaximum lengthnumber—
    label / invisibleLabelField label / label visually hidden (kept as accessible name)ReactNode / boolean— / false
    labelPositionLabel position'before' | 'after''after'
    iconIcon namestring—
    indicatorIndicator (falls back to required when required and not given explicitly)'up' | 'down' | 'clear' | 'required'—
    requiredRequired (native required attribute, part of browser validation)booleanfalse
    validateSoft validation (RegExp / function / symbolic name), see TextInput's soft validationRegExp | ((value: string) => boolean | Promise<boolean>) | 'non-empty' | 'integer'—
    readOnlyRead-only (keeps focus and selection/copying)booleanfalse
    disabledWhether disabledbooleanfalse
    flagsExtra flags on the root (the invalid flag is layered on top)string | string[]—
    nameForm field name (lands on <textarea>)string—
    accessKeyAccess key (lands on <textarea>)string—
    inputRefRef to the inner <textarea>Ref<HTMLTextAreaElement>—
    inputPropsExtra-props channel for the native <textarea>; onChange/onBlur/onFocus are chained after the component logicobject—
    indicatorPropsExtra props for the indicator elementobject—
    ...restNative div props (className, id, data-*, etc.) passed straight to the rootHTMLAttributes<HTMLDivElement>—

    See also