Make a text area fit its content automatically
Phuoc Nguyen
Posted on December 24, 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:
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:
.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:
.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.
const textareaStyles = window.getComputedStyle(textarea);
Next, we can loop through an array of common CSS properties and apply them to our mirrored element:
[
'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.
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:
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:
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.
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!
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:
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.
.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:
It's highly recommended that you visit the original post to play with the interactive demos.
If you found this series 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!
If you want more helpful content like this, feel free to follow me:
Posted on December 24, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
July 24, 2024