React Textarea

In the last lesson you learned about React Text Inputs, so you know how a single-line <input> works as a controlled component. This lesson is about the bigger box, the <textarea>, which works differently in React than in plain HTML, and we’ll use it to build a comment box with a live character counter.

🤔 Why is a textarea different from HTML?

A textarea in plain HTML and a textarea in React look the same, but you fill them in differently.

  • In plain HTML, the text you start with goes between the tags, like <textarea>hello</textarea>. So the text is the child of the element.
  • In React, you don’t do that. You set the text with the value prop instead, exactly like a normal input.
  • So the same value and onChange pattern you already know carries straight over. There’s nothing new to learn about the control itself.

So the only real change is where the text lives. In HTML it’s a child. In React it’s a prop.

✍️ A controlled textarea

Let’s see the wrong way and the right way side by side. The first is the HTML habit, the second is how React wants it.

import { useState } from "react";
function CommentBox() {
const [text, setText] = useState("");
// ❌ Wrong - HTML style, putting text between the tags does nothing useful in React
// <textarea onChange={(e) => setText(e.target.value)}>{text}</textarea>
// ✅ Right - use the value prop, just like an input
return (
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
/>
);
}

Let’s read what makes the right version work.

  • value={text} ties the box to your state, so what shows on screen is always whatever text holds.
  • onChange={(e) => setText(e.target.value)} runs on every keystroke and saves the new text back into state.
  • Putting the text between the tags like in HTML is the old habit. React ignores it for editing, so leave it out and use value.

Don't put the text between the tags

In React, writing the starting text as a child like a HTML textarea won’t behave the way you expect. Always set the text with the value prop instead.

📐 The rows attribute

A textarea is a multi-line box, so you usually want to say how tall it should be. That’s what rows is for. This box starts five lines tall, which is comfortable for a comment.

<textarea
value={text}
onChange={(e) => setText(e.target.value)}
rows={5}
/>

A couple of quick notes on rows.

  • rows={5} sets the visible height to about five lines of text. So it does not limit how much the user can type, it just sets the starting size.
  • The number goes inside curly braces because it’s a JavaScript value, not a plain string.
  • If the user types more than five lines, the box gets a scrollbar. So the rows value is only the starting height, not a hard cap.

🔢 A live character counter

Now for a really useful thing. Because the text lives in state, you always know its length, so you can show a live count as the user types. This comment box shows how many characters the user has typed so far.

import { useState } from "react";
function CommentBox() {
const [text, setText] = useState("");
return (
<div>
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
rows={5}
/>
<p>{text.length} characters</p>
</div>
);
}

Here’s the flow, step by step.

  • The user types, so onChange saves the new text into text.
  • React re-renders, and text.length reads the current number of characters.
  • The <p> shows that count, and it updates by itself on every keystroke.

Output

(user types "Great lesson")
Great lesson
12 characters

So the count stays in sync for free. You never count anything by hand, you just read the length of the text in state and React keeps it fresh.

📉 Showing characters remaining

Lots of comment boxes have a limit, like “max 200 characters”. You can show how many are left with the same idea, just subtracting from a limit. This version sets a limit and shows the characters remaining as the user types.

import { useState } from "react";
function CommentBox() {
const [text, setText] = useState("");
const limit = 200;
const remaining = limit - text.length;
return (
<div>
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
rows={5}
maxLength={limit}
/>
<p>{remaining} characters left</p>
</div>
);
}

Let’s break this one down.

  • limit is your maximum, and remaining is just limit - text.length. So it goes down as the user types.
  • maxLength={limit} tells the browser to stop accepting input once the limit is reached, so the user simply can’t type past it.
  • The <p> shows remaining, which counts down live and hits 0 when the box is full.

Two layers of safety

maxLength stops typing in the browser, and your remaining count tells the user where they stand. Using both gives a clear, friendly limit. You can also change the text color when remaining gets low to warn them.

🧩 What You’ve Learned

  • ✅ In plain HTML a textarea’s text goes between the tags, but in React you use the value prop instead
  • ✅ A controlled textarea uses the same value and onChange pattern as a normal input
  • ✅ Read the typed text from e.target.value inside onChange and save it in state
  • rows={5} sets the starting height of the box, but doesn’t limit how much can be typed
  • text.length gives a live character count for free, because the text lives in state
  • ✅ Subtract from a limit to show characters remaining, and use maxLength to stop typing past it

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    How do you set the text of a textarea in React?

    Why: Unlike plain HTML, a React textarea is controlled with the value prop, exactly like an input. Putting the text between the tags is the HTML habit and won't behave the way you expect.

  2. 2

    Inside onChange, how do you read what the user typed in a textarea?

    Why: e.target is the textarea that fired the event, so e.target.value is the current text. You usually save it into state with a setter.

  3. 3

    What does the rows attribute do on a textarea?

    Why: rows only sets the starting height of the box. If the user types more, the box just scrolls. To cap input, use maxLength.

  4. 4

    How do you show a live character count for a controlled textarea?

    Why: Because the text is in state, text.length always holds the current number of characters. React re-renders on each keystroke, so the count stays in sync by itself.

🚀 What’s Next?

Now you can handle a multi-line textarea as a controlled component and show a live counter. Next we’ll look at another kind of form control, where the user picks from a list of options instead of typing.

React Select Dropdowns

Share & Connect