← Back toMirror a text area

Make a text area fit its content automatically

Written byPhuoc Nguyen
Created
30 Sep, 2023
The text area on a website can be used for more than just basic input. For instance, it can be used for a comment section where users can leave feedback or a message box where users can compose an email. However, if the text overflows outside of the box, it can cause important information to be lost or cut off. To prevent this, we can implement an auto-sizing feature that adjusts the size of the text area based on its content.
In this post, we'll walk through how to automatically adjust the size of a text area on your website. With this feature, your users will have a seamless experience and be able to fully express themselves without any technical difficulties.

Cloning a text area

Let's talk about cloning a text area. We're going to use the mirroring technique we introduced in this series, but with a twist. Instead of creating a `div` element, we'll clone the original text area with another text area. This clone will mirror the content of our original text area and allow us to adjust its size automatically.
Here's some sample code:
js
const mirroredEle = document.createElement('textarea');
mirroredEle.classList.add('mirror');
document.body.appendChild(mirroredEle);
To position the clone, we'll use CSS to set its `position` property to `fixed`, which removes it from the normal document flow. Then, we'll set its `top` and `left` properties to `-9999px`, which places it far offscreen where it won't be visible to users. Finally, we'll set its `visibility` property to `hidden`, which ensures that the text area is not visible on the page.
Here's some sample code:
css
.mirror {
position: fixed;
top: -9999px;
left: -9999px;
visibility: hidden;
}
By using this technique, we can ensure that our mirrored text area doesn't interfere with the layout of our page while still allowing us to adjust its size based on its content.
But we're not done yet. We also need to disable the resize functionality of our original text area so that it doesn't interfere with the mirrored text area. We can do this with a simple CSS property:
css
.textarea {
resize: none;
}
By disabling resizing, we can prevent users from manually adjusting the size of the original text area and ensure that it remains consistent with our mirrored text area.

Mirroring styles

In order to make sure that our mirrored text area matches the style of the original text area, we need to copy its styles. To do this, we can use JavaScript's `getComputedStyle` function to retrieve all of the computed styles for our original text area.
js
const textareaStyles = window.getComputedStyle(textarea);
Next, we can loop through an array of common CSS properties and apply them to our mirrored element:
js
[
'border',
'boxSizing',
'fontFamily',
'fontSize',
'fontWeight',
'letterSpacing',
'lineHeight',
'padding',
'textDecoration',
'textIndent',
'textTransform',
'whiteSpace',
'wordSpacing',
'wordWrap',
].forEach((property) => {
mirroredEle.style[property] = textareaStyles[property];
});
By doing this, we can ensure that our mirrored text area looks and behaves just like the original text area, even if the content changes in size.

Resizing the text area

To resize the text area, we can use the `scrollHeight` property of a mirrored element. This property returns the height of all the content in the element, including any overflow beyond its visible boundaries.
js
const adjustSize = () => {
mirroredEle.textContent = textarea.value;
const newHeight = mirroredEle.scrollHeight +
borderTopWidth +
borderBottomWidth;
textarea.style.height = `${newHeight}px`;
};
Here's how it works. We start by setting the text content of our mirrored element to match that of the original text area:
js
mirroredEle.textContent = textarea.value;
Next, we calculate the new height for the original text area by adding the `scrollHeight` of our mirrored element to the sum of its top and bottom border widths:
js
const newHeight = mirroredEle.scrollHeight +
borderTopWidth +
borderBottomWidth;
We can calculate the border width of the original text area at the top and bottom using JavaScript. To do this, we can create a function that parses the computed style of the text area's border widths and extracts the values for its `border-top-width` and `border-bottom-width` properties.
js
const parseValue = (v) => v.endsWith('px')
? parseInt(v.slice(0, -2), 10)
: 0;
const borderTopWidth = parseValue(textareaStyles.borderTopWidth);
const borderBottomWidth = parseValue(textareaStyles.borderBottomWidth);
Finally, we set the `height` property of the original text area to this new height value. It's that simple!
js
textarea.style.height = `${newHeight}px`;

Automatically adjusting text area height

To make sure our text area adjusts its size when the user types or pastes content into it, we can add an event listener that detects these actions. JavaScript's `input` event is perfect for this:
js
textarea.addEventListener('input', () => {
adjustSize();
});
In this code, we use `adjustSize`, the function we defined earlier, to adjust the height of our text area based on the mirrored element's contents. By adding this listener, we can ensure that our text area's size updates automatically every time the user interacts with it.

Adding smooth animation to resizing

Now that we have a text area that adjusts its size based on content, let's make it look even more polished by adding a smooth animation to the resizing effect.
We can achieve this using CSS transitions. By adding the `transition` property to our original text area and setting it to `height 0.2s ease-in-out`, the height change of the text area will be animated over a duration of 0.2 seconds with an `ease-in-out` timing function.
css
.textarea {
transition: height 0.2s ease-in-out;
}
With this code in place, every time the text area resizes, it will do so smoothly and elegantly over the course of 0.2 seconds, giving your users a delightful experience.
Take a look at the final demo:
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