Allow text indentation on textarea in React

Let's suppose that you want to indent a line on a <textarea></textarea> in React.

Here is the skeleton:

jsx
import React, { useState } from 'react';

const TextareaInput = () => {

    const [text, setText] = useState({value: ''});

    const handleText = (e) => setText({value: e.target.value});

    return(
        <textarea
            onChange  = {handleText}
            value     = {text.value}
        />
    )

}

export default TextareaInput;

Adding some juice (🧃)

Add 2 properties to the text variable to control the position of the caret and the target element (textarea).

Furthermore, create a handleTab function and useEffect to accomplish the following:

  1. If the user presses the tab key; text indentation is done.
  2. Caret position updates after a text update.
jsx
import React, { useEffect, useState } from 'react';

const TextareaInput = ({spaces = 4}) => {

    const [text, setText] = useState({value: '', caret: -1, target: null});

    useEffect(() => {

        if(text.caret >= 0){

            text.target.setSelectionRange(text.caret + spaces, text.caret + spaces);

        }

    }, [text]);

    const handleTab = (e) => {

        let content = e.target.value;
        let caret   = e.target.selectionStart;

        if(e.key === 'Tab'){

            e.preventDefault();

            let newText = content.substring(0, caret) + ' '.repeat(spaces) + content.substring(caret);

            setText({value: newText, caret: caret, target: e.target});

        }

    }

    const handleText = (e) => setText({value: e.target.value, caret: -1, target: e.target});

    return(
        <textarea
            onChange  = {handleText}
            onKeyDown = {handleTab}
            value     = {text.value}
        />
    )

}

export default TextareaInput;

The useEffect Hook is triggered after a text update, but the caret is repositioned only if it's equal or greater than 0.

Thus, the caret will be repositioned only after a handleTab execution.

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.