Textarea

Mobile Support: Full
Jump to Props

A multi-line text input

Import

import { Textarea } from "@vitality-ds/components";

Usage

Textarea is used for multi-line text inputs, typically within a form. Examples of multi-line inputs include consult notes, invoice notes and comments. For a text input that only requires a single line, like a name, please see the Text Input component.

Unlike other input elements, the textarea uses the body font size in order to support longer blocks of text for clinical notes without using a lot of screen space.

Building a form? See Form Field for more information on how to use Textarea within a form.

Name, value and id

If being used as a stand alone component, Textarea must be passed a name, value and id. When used with FormField, these props are passed down from FormField and don't need to be passed again.

  • name is a descriptive title for the data expected to be received from the textarea. A Textarea for patient notes would have the name patientNotes for example.
  • value is what has been input to the Textarea. Value can also represent default or existing data to prepopulate a textarea in the case of updating data. Name and value work together in the same way a key: value pair work together in an object.
  • id is an identifier that enables a label to be associated with the Textarea and aides in accessibility.
() => {
  const [value, setValue] = React.useState(
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin in est a tortor facilisis dapibus. Etiam et magna dolor. Ut varius finibus nulla."
  );

  return (
    <Textarea
      value={value}
      name="dailyReflection"
      id="dailyReflection"
      onChange={(event) => setValue(event.target.value)}
    />
  );
};

onChange function

The callback function passed to the component that triggers on every change event. A typical use case is to set a state with the new value. An event object can be retrieved from the Textarea.

Read more about HTML change events.

() => {
  const text = "Lorem ipsum dolor sit amet.";

  const [value, setValue] = React.useState(text);

  function changeHandler(event) {
    setValue(event.target.value);
  }

  return (
    <Textarea
      value={value}
      name="dailyReflection"
      id="dailyReflection"
      onChange={changeHandler}
    />
  );
};

Placeholder

Placeholder text is a great way to communicate the structure of data you would expect to be input into Textarea. Placeholder text should be used sparingly and never in place of a label as this affects both accessiblity and user experience. Placeholder text disappears once you enter a value, so be sure to consider if it's the best solution for the scenario - often helper text is an appropriate alternative.

Avoid
  • Using placeholder text as a label or helper message
() => {
  const [value, setValue] = React.useState("");

  return (
    <Stack>
      <label htmlFor="previousInjuries">Previous injuries</label>
      <Textarea
        placeholder="- Injury \n- Injury \n- Injury"
        value={value}
        name="previousInjuries"
        id="previousInjuries"
        onChange={(event) => setValue(event.target.value)}
      />
    </Stack>
  );
};

Disabled

A Textarea can be disabled by passing a boolean value to the disabled prop. This will grey out the textarea and disable any interaction with the input.

() => {
  const [value, setValue] = React.useState(
    "This is a disabled textarea that can't be edited."
  );

  return (
    <Textarea
      disabled
      value={value}
      name="disabledTextarea"
      id="disabledTextarea"
      onChange={(event) => setValue(event.target.value)}
    />
  );
};

Forwarding refs

Should the parent ref need to be passed to the Textarea, create the ref locally and pass the prop.

() => {
  const parentRef = React.useRef();
  const [value, setValue] = React.useState("");

  return (
    <Textarea
      ref={parentRef}
      value={value}
      name="refTextarea"
      id="refTextarea"
      onChange={(event) => {
        (parentRef.current.style.backgroundColor = "hsl(187, 46%, 78%)"),
          setValue(event.target.value);
      }}
    />
  );
};

Resize

Use the resize prop to determine how (or if) the textarea will grow/shrink with changes in the amount of input text. Resize defaults to smart which will dynamically grow and shrink as text is added or removed.

() => {
  const [smartResizeValue, setSmartResizeValue] = React.useState(
    "Smart resize (default) - will grow and shrink with the text"
  );
  const [autoResizeValue, setAutoResizeValue] = React.useState(
    "Auto resize - manually resize textarea both horizontally and vertically"
  );
  const [verticalResizeValue, setVerticalResizeValue] = React.useState(
    "Vertical resize - manually change the height of the textarea"
  );
  const [horizontalResizeValue, setHorizontalResizeValue] = React.useState(
    "Horizontal resize - manually adjust the width of the textarea"
  );
  const [noResizeValue, setNoResizeValue] = React.useState(
    "No resize - the textarea will maintain its size no matter how much text is input"
  );
  const [noResizeShortValue, setNoResizeShortValue] = React.useState(
    "No resize - adjust the static size by using the minRows prop"
  );

  return (
    <Stack>
      <Stack direction="horizontal">
        <Textarea
          resize="smart" // default, does not need to be passed
          value={smartResizeValue}
          name="resizeDemo"
          id="resizeDemo"
          onChange={(event) => setSmartResizeValue(event.target.value)}
        />
        <Textarea
          resize="auto"
          value={autoResizeValue}
          name="resizeDemo"
          id="resizeDemo"
          onChange={(event) => setAutoResizeValue(event.target.value)}
        />
      </Stack>
      <Stack direction="horizontal">
        <Textarea
          resize="vertical"
          value={verticalResizeValue}
          name="resizeDemo"
          id="resizeDemo"
          onChange={(event) => setVerticalResizeValue(event.target.value)}
        />
        <Textarea
          resize="horizontal"
          value={horizontalResizeValue}
          name="resizeDemo"
          id="resizeDemo"
          onChange={(event) => setHorizontalResizeValue(event.target.value)}
        />
      </Stack>
      <Stack direction="horizontal">
        <Textarea
          resize="none"
          value={noResizeValue}
          name="resizeDemo"
          id="resizeDemo"
          onChange={(event) => setNoResizeValue(event.target.value)}
        />
        <Textarea
          resize="none"
          minRows={2}
          value={noResizeShortValue}
          name="resizeDemo"
          id="resizeDemo"
          onChange={(event) => setNoResizeShortValue(event.target.value)}
        />
      </Stack>
    </Stack>
  );
};

Minimum rows

There may be occasions where the default 4 rows of text is too tall or short for the space Textarea is being used in. 4 rows may also inaccurately represents the amount of data you would expect to receive - for example when expecting an address, 2 rows is more suitable, or if expecting a diary entry, 4 rows may not seem like enough. In this case, pass a numeric value to minRows to set the desired minimum.

Note that while it is possible to pass a value of 1, consider if there's a real use case for this. If only 1 line of text is expected to be input, use a Text Input instead. The default maximum rows is set to 20, so keep this in mind if setting the minRows to a high number.

() => {
  const [address, setAddress] = React.useState(
    "1/100 Road Name Rd\nBrisbane QLD 4000"
  );

  return (
    <Stack>
      <label htmlFor="address">Address</label>
      <Textarea
        minRows={2}
        value={address}
        name="address"
        id="address"
        onChange={(event) => setAddress(event.target.value)}
      />
    </Stack>
  );
};

Maximum rows

Similarly to minimum rows, there may be a time where it's important to ensure the Textarea does not grow all the way to the default maximum of 20, or needs to grow beyond 20 lines. In this case, pass a numeric value to represent the maximum number of lines before the Textarea stops growing and instead offers a scroll bar for any overflow. Applies to both auto and manual resizing.

() => {
  const notes =
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin in est a tortor facilisis dapibus. Etiam et magna dolor. Ut varius finibus nulla et imperdiet. Lorem ipsum dolor sit amet. \n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Proin in est a tortor facilisis dapibus. Etiam et magna dolor. Ut varius finibus nulla et imperdiet. Lorem ipsum dolor sit amet.";

  return (
    <Stack>
      <label htmlFor="patientNotes">Patient notes</label>
      <Textarea
        maxRows={8}
        value={notes}
        name="patientNotes"
        id="patientNotes"
        onChange={(event) => console.log(event.target.value)}
      />
    </Stack>
  );
};

Error state

Textarea has an error state hasError which is a boolean value that changes the styling based on failed validation. Pass hasError to enable the error state.

() => {
  const [value, setValue] = React.useState("This textarea failed validation");
  const [error, setError] = React.useState(true);

  return (
    <Textarea
      value={value}
      hasError={error}
      name="invalidTextarea"
      id="invalidTextarea"
      onChange={(event) => setValue(event.target.value)}
    />
  );
};

Other HTML attributes

Any other valid HTML <textarea> attributes can be passed to the Textarea component, and would be expected to perform the same as the native jsx element. See the MDN Docs for more information.

() => {
  const [value, setValue] = React.useState("");

  return (
    <Stack>
      <Textarea
        // max length is a HTML attribute that will limit the allowed characters
        maxLength={10}
        value={value}
        name="textareaName"
        id="textareaName"
        onChange={(event) => setValue(event.target.value)}
      />
    </Stack>
  );
};

Figma Library

Figma.logo

Textarea Props

disabled

Description

Use this prop to disable the textarea. Disabled textarea's cannot be clicked on, changed, or have text interacted with at all.

Type

boolean

Default Value

false

hasError

Description

Optional prop that adds additional 'critical' styling to indicate if the input has failed validation.

Type

(boolean | "true"

Default Value

false

id

Description

The id of the textarea, used to pair the label with the input

Type

string

maxRows

Description

Optional prop to set a maximum number of rows on the textarea. If more text is input than space allows, a scroll bar will appear.

Type

number

Default Value

20

minRows

Description

Optional prop to set a minimum number of rows on the textarea. Even if no text is input, the textarea will still appear this height. Useful to override the default height if smaller space is available.

Type

number

Default Value

4

name

Description

The name of the textarea, eg 'consultNotes' to describe what the textarea is for

Type

string

onChange

Description

Function triggered on change event

Type

ChangeEventHandler<HTMLTextAreaElement> & ((event: HTMLInputElement) => void)

resize

Description

Handles how the textarea resizes depending on the amount of input text.

Type

("none" | "auto" | "vertical" | "horizontal" | "smart"

Default Value

smart

value

Description

The value of the textarea. I.e. entered text or retrieved data

Type

(string | number | readonly string[]) & string

© 2025