DEV Community

Cover image for Make a text area fit its content automatically
Phuoc Nguyen
Phuoc Nguyen

Posted on • Originally published at phuoc.ng

Make a text area fit its content automatically

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);
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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];
});
Enter fullscreen mode Exit fullscreen mode

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`;
};
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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`;
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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:

Top comments (4)

Collapse
 
chrishow profile image
Chris How

👏

(Did you miss the transition property on the codepen?)

Collapse
 
phuocng profile image
Phuoc Nguyen

Can you let me know which element should come with the transition property?
I see the pen is working without any issues.

Collapse
 
chrishow profile image
Chris How

In the 'Adding smooth animation to resizing' section, you mention a 'transition' property added to the textarea, but it's not there in the final demo.

Thread Thread
 
phuocng profile image
Phuoc Nguyen

Thank a lot. The pen is updated.