'Vue 3 Composition API - How to get the component element ($el) on which component is mounted
I want to use onMounted
to initiate 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 1:[1]
tl;dr:
In Vue 3, components are no longer limited at 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 setup
function, you should instantiate root
as const root = ref(null)
.
In 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 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 ref
erence 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>
Solution 2:[2]
In Vue 3 + Composition API there is no $el
alternative provided.
Even if you use Vue 3 with Options API, due to the availability of Fragments, it is recommended to use template refs for direct access to DOM nodes instead of relying on this.$el
.
How to initiate a third-part-library
Let's say we have a div element for the third-part-library:
<template>
Below we have a third-party-lib
<div class="third-party-lib"></div>
</template>
And then we want to initiate it from the Javascript:
Solution 1 (recommended): Using template refs
<script setup>
import { ref, onMounted } from 'vue';
const $thirdPartyLib = ref(null); // template ref
onMounted(() => {
$thirdPartyLib.value.innerText = 'Dynamically loaded';
});
</script>
<template>
Below we have a third-party-lib
<div ref="$thirdPartyLib" class="third-party-lib"></div>
</template>
Solution 2 (not recommended): Using non-documented
@VnodeMounted
<script setup>
function initLib({ el }) {
el.innerText = 'Dynamic content';
}
</script>
<template>
Below we have a third-party-lib
<div class="third-party-lib" @VnodeMounted="initLib"></div>
</template>
Solution 3:[3]
Just adding my 2 cents here, and wanted to correct what some other answers are saying that Vue 3 does not have $el
anymore.
It does still have it: https://vuejs.org/api/component-instance.html#el.
Its use is discouraged in case of multi-root where the $el
element can't be decided to a specific root element, and for consistency with single-root components (where $el works the same way as Vue 2), the documentation suggests that you use $refs instead.
For multi-root components, the $el
ref is on a the closest text node before the elements (or comment for SSR hydration).
It does not mean that $el
is unreliable, au contraire, since this mechanism is used internally and for SSR hydration.
In most cases, you can use $refs
and you should.
But if you can't, like in the case below, you can still rely on $el
:
<template>
# an empty text node exists here in the DOM.
<slot name="activator" :on="activatorEventHandlers">
<other-component />
</template>
In this case (case of tooltips and context menus where an event listener is attached to a user slot), the first element is a slot, and you can't add a ref on a slot.
So using $el
will point to the first text node, so this.$el.nextElementSibling
will be the element given through the user slot.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | antoni |