Search code examples
vue.jsvue-composition-apivuejs3

Vue 3 Composition API - How to get the component element ($el) on which the component is mounted?


I want to use onMounted to initiate a third-party library. To do that I need the component element as its context. In Vue 2 I would get it with this.$el but not sure how to do it with composition functions. setup has two arguments and none of them contains the element.

setup(props, context) {
    onMounted(() => {
        interact($el)
            .resizable();
    })
}

Solution

  • tl;dr:

    In Vue 3, components are no longer limited to only 1 root element. Implicitly, this means you no longer have an $el.

    You have to use ref to interact with any element in your template:

    <div ref="root" />
    

    In the setup function, you should instantiate root as const root = ref(null).

    In the Options API, you can just use this.$refs.root in any method or hook, as long as it's after mounted().

    As pointed out by @AndrewSee in the comments, when using a render function (not a template), you can specify the desired ref in createElement options:

    render: function (createElement) {
      return createElement('div', { ref: 'root' })
    }
    // or, in short form:
    render: h => h('div', { ref: 'root' })
    

    initial answer:

    As outlined in docs,

    [...] the concepts of reactive refs and template refs are unified in Vue 3.

    And you also have an example on how to ref a "root" element. Obviously, you don't need to name it root. Name it $el, if you prefer. However, doing so doesn't mean it will be available as this.$el, but as this.$refs.$el.

    <template>
      <div ref="root"></div>
    </template>
    
    <script>
      import { ref, onMounted } from 'vue'
    
      export default {
        setup() {
          const root = ref(null)
    
          onMounted(() => {
            // the DOM element will be assigned to the ref after initial render
            console.log(root.value) // this is your $el
          })
    
          return {
            root
          }
        }
      }
    </script>
    

    In Vue 3 you're no longer limited to only one root element in <template>, so you have to specifically reference any element you want to interact with.


    Update, 2 years later.
    Specific syntaxes for various component styles (they are not different solutions, they are different ways of writing the same thing):

    <script setup>:

    <script setup>
    import { ref, onMounted } from 'vue';
    const root = ref(null);
    onMounted(() => console.log(root.value.outerHTML));
    </script>
    <template>
      <div ref="root" />
    </template>
    

    <script setup lang="ts">:

    <script setup lang="ts">
    import { ref, onMounted } from 'vue';
    const root = ref<HTMLElement | null>(null);
    onMounted(() => console.log(root.value?.outerHTML));
    </script>
    <template>
      <div ref="root" />
    </template>
    

    Options API:

    <script>
      export default {
        mounted() {
          console.log(this.$refs.root.outerHTML);
        }
      }
    </script>
    <template>
      <div ref="root" />
    </template>