Exercise: Tracked Textarea

Exercise 15 Easy

Prerequisites for the exercise

  1. React Uncontrolled Components

Objective

Create a TrackedTextarea component that tracks the length of characters entered into a <textarea> element.

Description

We are all familiar with the <textarea> element from HTML. It is used to represent a large input block where we can enter mere textual data.

The maxlength attribute of a <textarea> is used to specify the maximum number of characters that could be entered into it.

For example, the following <textarea> has a maxlength of 10, hence we could enter no more than 10 characters in it:

As we try to enter more than 10 characters into it, the surplus data is trimmed off.

Suppose we explicitly mention the current character length along with the maximum length allowed right below the <textarea>, as follows:

0 / 10

To fancy it, we could say that the <textarea> is now a 'tracked textarea', as its length is being tracked.

In this exercise, you have to create a TrackedTextarea component that renders a <textarea> and writes its current length along with its max length out on the document.

Here's how the length must be displayed: current length / max length. So, for instance, if the current length is 12 and the maximum allowed is 40, we should see 12 / 40.

You should use a normal <p> element nested with a <small> element to hold this length information.

Most importantly, the underlying <textarea> must be uncontrolled.

Here are a couple of points to follow regarding the props of TrackedTextarea:

  • A maxLength prop specifies the maximum length of the <textarea>. By default, it's 100. This prop is also meant to delegated down to the rendered <textarea>.
  • A value prop, if given, specifies the initial value of the <textarea>.
  • However, this value prop should NOT be provided to the underlying <textarea> in order to meet the first requirement above. You have to think of something else to apply an initial value without making the <textarea> controlled.
  • If the given value prop has more characters than the maximum allowed length of the TrackedTextarea component, as with the normal behavior in HTML, the value must be presented as it is without truncation.
  • Any other prop provided must be delegated down to <textarea>. For example, if we provide a placeholder to TrackedTextarea, it should be provided to <textarea> as well.

Here's a dummy code to test the component:

function App() {
   return (
      <TrackedTextarea value="Initial" maxLength={5} />
   );
}

Here's how the final result should look:

Live Example

Notice how the initial value, i.e. 'Initial' (7 characters long) is larger in length than the given maxLength, yet it is displayed without truncation (as asked in the description above).

Hints

Hint 1

The value prop of TrackedTextarea should be delegated down to the defaultValue prop of the <textarea>.

Hint 2

Create a length state to keep track of the length of the text entered into the <textarea>.

View Solution

New file

Inside the directory you created for this course on React, create a new folder called Exercise-15-Tracked-Textarea and put the .js solution files for this exercise within it.

Solution

Since the exercise has clearly asked us not to make the <textarea> controlled, it's evident that we don't need to keep track of its value or assign it a value prop — the DOM should take care of this on its own.

What we need is an onChange handler assigned to the <textarea> that reads the length of the data currently entered into it and outputs it on the document along with the provided maxLength prop.

To keep track of this length, we'll create a length state, initialized to value.length, where value represents the initial value to render in the <textarea>.

Coming to this value prop (provided to the TrackedTextarea component), we need to provide it to the defaultValue prop of the <textarea>. Remember that we can't use the value prop on <textarea> because doing so would otherwise make the component controlled and that is against the instructions given above.

With all this plan in hand, let's get to implementing TrackedTextarea.

Here's the complete definition of TrackedTextarea:

import { useState } from 'react';

function TrackedTextarea({
   maxLength = 100,
   value,
   ...props
}) {
   const [length, setLength] = useState(value.length);

   return (
      <>
         <textarea
            maxLength={maxLength}
            defaultValue={value}
            onChange={e => setLength(e.target.value.length)}
            {...props}
         />
         <p><small>{length} / {maxLength}</small></p>
      </>
   );
}

Let's try running this:

Live Example

Voila! It works flawlessly!

And this completes this exercise.