Creating an auto resizing textarea with Vue Composition API in 4 easy steps. I can't wait for Vue v3
Tags: vue, beginners, tutorial, typescript
Published: 2020-02-07 23:30:57

---
title: Creating an auto resizing textarea with Vue Composition API in 4 easy steps. I can't wait for Vue v3
published: true
description: Here's a quick way to create an auto resizing textarea with Vue Composition API.
tags: vue, beginners, tutorial, typescript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/5tnlidfii4cqttfa1q4j.jpg
---
I'm assuming you now know how to add [@vue/composition-api](https://github.com/vuejs/composition-api) to your project so I won't waste any more time.

### Step 1
Where ever you need to, in your template, just add the textarea element like so:
```vue
<template>
    <!-- anything else you probably had -->
    <textarea ref="myTextArea" v-model="content"></textarea>
</template>
```
Notice we added a `ref` attribute. name it whatever you like. Don't forget the v-model.

### Step 2
Create the composition function. I created mine inside the same component file I created the textarea in. You can even create a separate file for it if you like.

```typescript
function useTextArea() {
  const myTextArea = ref<HTMLTextAreaElement>([]); // remove <...> if JS
  const content = ref("");

  return { myTextArea, content };
}

```
If not done automatically by your editor, add the following import statement
```typescript
import { createComponent, ref, watch } from "@vue/composition-api";
// remember 'createComponent' is not needed/used in javascript
```

### Step 3
Expose these properties to your Vue template. We do that in the setup function's return statement
```typescript
export default createComponent({
  // ... other things you did.
  setup(props, context) {
    // ... some other stuff
    const { myTextArea, content } = useTextArea();
    // ... maybe some more stuff, I don't know
    return {
      // ... maybe other things are here too, your things
      myTextArea,
      content
    };
  }
}) as VueConstructor;
```
I usually add `as VueContructor` just to stop the noise from eslint and vue-router complaining about the component's expected type. Not really a requirement.

Ok everything is neat now, there should be no errors but nothing works yet. We do however have a [reference](https://vuejs.org/v2/api/#ref) without having to use `this.$refs` bacause obviously we don't have access to `this` in our setup function. But through the magic of the composition api, the concept of refs is unified.

### Step 4
Making it work. We go back to the `useTextArea` function to add a couple of lines to watch for changes in the textarea's content and calculate the element's new height after that.
```typescript
function useTextArea(){
  // ... after variable declarations
  watch(() => {
    if (content.value.length === 0) return;
    myTextArea.value.rows = 2; // depends on what you want initially
    const styles = window.getComputedStyle(myTextArea.value);
    const paddingTop = parseInt(styles.paddingTop);
    const paddingBottom = parseInt(styles.paddingBottom);
    const padding = paddingTop + paddingBottom;
    const currentHeight = parseInt(styles.height) - padding;
    const initialHeight =
      (parseInt(styles.height) - padding) / myTextArea.value.rows;
    const scrollHeight = myTextArea.value.scrollHeight - padding;
    const newRows = Math.ceil(scrollHeight / initialHeight);
    textArea.value.rows = newRows;
  });
  // ... before the return statement
}
```
Aaand done. You now have a textarea that adds or removes rows if there are any changes with it's value. You don't have to know off hand, the height of your element or the font size of the content, which can change anytime.

One concern I have is just the performance of the code inside the `watch` function. If you have a better implementation please link it in the comments, I'd love to see different ideas around this. I've never enjoyed writing VueJS like this ever before.