← Back toHTML DOM

Remove indentation in a text area using the Shift+Tab key combination

Written byPhuoc Nguyen
03 Oct, 2023
Level 2 — Intermediate
Do you ever get frustrated when the Tab key adds unwanted indentation to your code in a textarea? Or maybe you want to remove some of the existing indentation? Fear not, my friend. One solution is to allow users to use the Shift+Tab key combination to remove the indentation.
This trick comes in handy when writing code for a website or application. Proper indentation is crucial for keeping your code organized and easy to read. But if you accidentally hit the Tab key too many times or need to remove some of the existing indentation, manually deleting each extra space or tab is a time-consuming hassle.
This problem also shows up when filling out forms online that require text in a textarea. If you accidentally add extra spaces or tabs at the beginning of a new line, it can mess up the formatting when you submit the form. But with the Shift+Tab key combination, you can easily fix these errors without deleting each space or tab one by one.
In this post, we'll explore how to implement this functionality using JavaScript.

Detecting the Shift+Tab key combination

In order to detect when a user presses the Shift+Tab keys, we need to listen for the keydown event on the textarea. When this event fires, we can check if both the Shift and Tab keys are being pressed. We can do this by comparing the `key` property of the event object to the string `Tab` and checking if the `shiftKey` property is set to `true`. If both conditions are met, we know that the Shift+Tab keys were pressed. This allows us to trigger our function for removing indentation and prevent the default behavior of pressing the Tab key.
Here is a sample code snippet to give you an idea. Don't worry, we'll cover the `removeIndentation` function in the next section.
textarea.addEventListener('keydown', (e) => {
if (e.key === 'Tab' && e.shiftKey) {
// Shift+Tab are pressed

Removing indentation

When you detect the Shift+Tab key combination, it's time to remove the indentation from the selected text. This can be done by getting the current value of the textarea, finding the selected text, and replacing the leading whitespace with empty strings.
To make it easy, we've created a `removeIndentation` function that will take care of the indentation removal for you. It first gets the current value of the text area, as well as the start and end positions of the selected text.
const removeIndentation = () => {
const { value, selectionStart, selectionEnd } = textarea;
// ...
Next, we need to determine the range of selected lines by creating a new array called `linesBeforeCaret` first. We do this by using `.substring()` on `value` to get all the characters before `selectionStart`. Then, we split that string into an array using `.split('\n')`, which gives us an array with only the lines before the selected text.
To calculate the starting line, we get the length of `linesBeforeCaret` and subtract one. We subtract one because arrays are zero-indexed, but we want to count actual lines starting from one. For example, if there are two lines before our selection starts, then our starting line is actually three.
Similarly, we can calculate the end line by getting all the characters before `selectionEnd`, splitting them into an array using `.split('\n')`, and then counting how many items are in that array. We also subtract one from this count for the same reasons mentioned above.
Here's some sample code to help you visualize it all:
const linesBeforeCaret = value.substring(0, selectionStart).split('\n');
const startLine = linesBeforeCaret.length - 1;
const endLine = value.substring(0, selectionEnd).split('\n').length - 1;
Next, we split a text area's value into an array of lines and check if each line falls within the range determined earlier and starts with a tab character.
If a line meets these conditions, we remove the leading tab character using JavaScript's `substring` method. Then, we join all lines back into a single string and set that as the new value of the textarea. We also adjust the cursor's position so that it remains on the same line after removing indentation. If necessary, we move it back by one tab character to align it with any other code on that line.
const newValue = value
.map((line, i) => i >= startLine && i <= endLine && line.startsWith('\t') ? line.substring(1) : line)
textarea.value = newValue;

Updating the cursor position

It's important to update the `selectionStart` and `selectionEnd` properties in the `removeIndentation` function. These properties tell us where the selected text begins and ends within the text area.
When we remove indentation, the length of each line may change, which means the start and end positions of our selected text will also change. If we don't update these positions, our cursor will be positioned incorrectly after removing indentation.
By updating the selection properties, we ensure that our cursor remains on the same line after removing indentation. This makes it easier to continue typing or editing code without having to manually adjust your cursor position.
To calculate the new values of `selectionStart` and `selectionEnd`, we need to consider the number of characters removed due to the indentation removal. We do this by subtracting the length of the original text area value from the length of the new value after removing indentation. The difference gives us the total number of removed characters. We then subtract this number from `selectionEnd` to get its new value.
textarea.selectionEnd = selectionEnd - (value.length - newValue.length);
For `selectionStart`, we check if the start line had any leading whitespace. If it did, we subtract the length of the tab character from `selectionStart`. Otherwise, `selectionStart` remains unchanged.
const startLineText = linesBeforeCaret[startLine];
textarea.selectionStart = startLineText?.startsWith('\t')
? selectionStart - 1
: selectionStart;
Let's check out the final demo. To add indentation, just hit the Tab key, and to remove it, hit Shift+Tab. Give it a try!

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