Make a text area fit its content automatically
Tags: tutorial, javascript, webdev
Published: 2023-12-24 11:54:28

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](https://phuoc.ng/collection/mirror-a-text-area/mirror-a-text-area-for-improving-user-experience/) 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:

{% codepen https://codepen.io/phuocng/pen/MWxYWaP %}

---

It's highly recommended that you visit the [original post](https://phuoc.ng/collection/mirror-a-text-area/make-a-text-area-fit-its-content-automatically/) to play with the interactive demos. 

If you found this series helpful, please consider giving the [repository](https://github.com/phuocng/mirror-a-text-area) 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:

-   [Twitter](https://twitter.com/_phuocng)
-   [GitHub](https://github.com/phuocng)