← Back toHTML DOM

Indent content in a text area using the Tab key

Written byPhuoc Nguyen
Created
20 Sep, 2023
Last updated
03 Oct, 2023
Category
Level 2 — Intermediate
Adding indentation to a text area can make a big difference in real-life scenarios. For example, programmers write code snippets or scripts within a text area and use the tab key to indent different parts of their code, making it easier to read and understand.
Similarly, students may need to submit essays or research papers online and use text areas for submissions. Indenting paragraphs or bullet-pointed lists within these text areas can help students better organize their thoughts and ideas.
In this post, we'll learn how to insert indentation by pressing the Tab key.

Adding indentation

To add indentation, simply add an event listener to the text area and detect when the `Tab` key is pressed. Then, insert a tab character (`\t`) into the text area at the current cursor position. This way, you can easily add indentation without having to reach for the space bar multiple times.
js
const textarea = document.querySelector("textarea");

const insertTabCharacter = () => {
const { value, selectionStart, selectionEnd } = textarea;

// Insert tab character
textarea.value = `${value.substring(0, selectionEnd)}\t${value.substring(selectionEnd)}`;

// Move cursor to new position
textarea.selectionStart = textarea.selectionEnd = selectionEnd + 1;
};

textarea.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
insertTabCharacter();
}
});
Once we insert a tab character, we want the user to keep typing without any interruption. To achieve this, we move the cursor to the new position by setting both the `selectionStart` and `selectionEnd` properties of the text area to `selectionEnd + 1`. This ensures that the cursor is placed immediately after the inserted tab character.
Want to see it in action? Check out the demo below.

Adding indentation to each line of selected text

When implementing a solution that involves using the `Tab` key for indenting text areas, it's important to consider a potential issue. If a user has selected some text within the text area and then presses the `Tab` key, the selected text will be replaced with a tab character instead of being indented.
To avoid this problem, we can check if there is any text currently selected in the text area before inserting the tab character. We can achieve this by comparing the `selectionStart` and `selectionEnd` properties. If they are equal, then no text is currently selected. If they are different, then there is some text selected within the text area.
js
(selectionStart === selectionEnd)
// Insert tab character
? insertTabCharacter()
// Add indentation to each line of selected text
: addIndentation();
In our updated code snippet, we first check if there is any selected text before deciding whether to insert a tab character or add indentation to each line of the selected text. This ensures that we don't accidentally replace any selected text with a tab character.
Here's the updated code to take care of the issue:
js
const textarea = document.querySelector('textarea');

// Add indentation to each line of selected text
const addIndentation = () => {
// ...
}

textarea.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
const { selectionStart, selectionEnd } = textarea;
(selectionStart === selectionEnd)
? insertTabCharacter()
: addIndentation();
}
});
In the `keydown` event handler example, the function checks the starting and ending positions of the selection. If the positions are different, it means that you have selected some text in the text area. In such cases, the `addIndentation` function is used to add indentation to each line of the selected text.
First, we first need to split the text into lines before and after the selection.
js
const addIndentation = () => {
const { value, selectionStart, selectionEnd } = textarea;
const linesBeforeCaret = value.substring(0, selectionStart).split('\n');
const startLine = linesBeforeCaret.length - 1;
const endLine = value.substring(0, selectionEnd).split('\n').length - 1;
};
Then, we calculate which lines are within the selection. For each selected line, we add a tab character at the beginning using template literals. Finally, we reconstruct the entire string by joining all lines with newline characters and set this new value as the value of the textarea element.
js
const newValue = value
.split('\n')
.map((line, i) => (i >= startLine && i <= endLine) ? `\t${line}` : line)
.join('\n');
textarea.value = newValue;
To ensure that the cursor stays in place relative to the newly added indentation, we need to adjust both `selectionStart` and `selectionEnd`. First, we calculate `newSelectionStart` by checking if the starting line of the selection contains any non-whitespace characters. If it does, then we add 1 to `selectionStart`, which moves the cursor one position to the right. Otherwise, `newSelectionStart` remains equal to `selectionStart`.
js
const startLineText = linesBeforeCaret[startLine];
const newSelectionStart = startLineText && /\S/.test(startLineText)
? selectionStart + 1
: selectionStart;
Next, we calculate `newSelectionEnd` by adding to `selectionEnd` the number of lines that were modified by inserting a tab character at the beginning of each selected line. Specifically, `(endLine - startLine + 1)` gives us the number of lines in the selection that were modified.
js
const newSelectionEnd = selectionEnd + (endLine - startLine + 1);
By adjusting both `selectionStart` and `selectionEnd`, we ensure that the cursor stays in its original position relative to the newly indented text.
Now you can safely use the `Tab` key to add indentation to your text areas without worrying about accidentally replacing selected text.
Take a look at the final demo below:

Conclusion

With this code implementation, users can now use the `tab` key to effortlessly indent their text within the text area. This seemingly small change can vastly improve the readability and organization of user-submitted content.

See also

If you found this post helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

Questions? 🙋

Do you have any questions about front-end development? If so, feel free to create a new issue on GitHub using the button below. I'm happy to help with any topic you'd like to learn more about, even beyond what's covered in this post.
While I have a long list of upcoming topics, I'm always eager to prioritize your questions and ideas for future content. Let's learn and grow together! Sharing knowledge is the best way to elevate ourselves 🥷.
Ask me questions

Recent posts ⚡

Newsletter 🔔

If you're into front-end technologies and you want to see more of the content I'm creating, then you might want to consider subscribing to my newsletter.
By subscribing, you'll be the first to know about new articles, products, and exclusive promotions.
Don't worry, I won't spam you. And if you ever change your mind, you can unsubscribe at any time.
Phước Nguyễn