What are Vue instance properties?
When defining a new Vue instance, the constructor function accepts an object as a parameter through which all Vue instance options are defined. Within that object, Vue.js already provides predefined properties each with its own characteristics, which enable the operation of the Vue application. The following list represents the basic properties of each Vue instance and are accessed outside the instance with the $ sign.
Next to them, three very important properties are mentioned: computed, methods and watch which act as proxies (read more about this in the article “Accessing Vue instance properties”).
“$el”
As of version 3.0 $el can be used to access the underlying DOM element, mostly with components that use fragments. However, it is recommended that starting with version 3.0, the reliance on $el should be avoided, but instead the template references $refs should be used as direct access to DOM elements.
Within the 2.0 version with the property “el” we define the HTML element that will be “managed” by the Vue application:
HTML
|
1 |
<div id="some Selector"></div> |
JavaScript
|
1 2 3 |
new Vue ({ el: "#nekiSelektor" }) |
“$data”
Vue 3 note (2026): this.$set / Vue.set are unnecessary in Vue 3 (Proxy-based reactivity). Assign properties directly. Keep $set only for Vue 2 code.
- Options API
-
Composition API
At the “Options API” within the “options object” there is a property “data” (“model” in MVVM) which represents a section related to accessing and storing data. Vue.js recursively converts all properties from the “data” object to getter/setters to make them “reactive”. The “data” object must be simple to represent only data, so all API objects of the browser (window, document…), as well as prototype properties of the object, are ignored by Vue.js.
Properties starting with _ (underscore) or $ (dollar sign) will not act as proxies to Vue instances, as such names conflict with internal Vue.js properties and methods.
The data property has specific privileges and acts as a “proxy” to the Vue instance. This means that they pass their child properties directly to the Vue instance, and the result of this behavior is that its child properties are so-called. “top properties” (first to instance), which can be accessed directly with the “this” keyword. Read more about this in the article “Accessing Vue.js Instance Properties”
Example
In version 3.0 “data” is not an object but a function that returns variables, see example:
|
1 2 3 4 5 6 7 8 9 |
let app = Vue.createApp({ data () { return { msg: "Some text" } } }); let vm = app.mount("#app") |
Or with direct instantiation like this:
|
1 2 3 4 5 6 7 8 9 10 11 |
// direct instance creation const data = { a: 1 } // The object is added to a component instance const vm = createApp({ data() { return data } }).mount('#app') console.log(vm.a) // => 1 |
Example (3.0 ver):
In version 2.0 “data” is a standard object property, which is just an object, see prime:
|
1 2 3 4 5 6 |
var vm = new Vue({ data: { a: 1, b: 3 } }) |
or
|
1 2 3 4 5 6 7 8 |
var podaci = { a: 1, b: 3 } var vm = new Vue({ data: podaci }) |
Reactive data properties can no longer be added after Vue instance creation. Therefore, it is recommended to define such properties in advance, before the instance is created (so that Vue.js can process them anddefined as reactive). It should be noted that although the so-called “root-level” reactive properties, it is possible to subsequently add new properties within the already defined “root-level” reactive properties with the following syntax:
|
1 |
this.$set(this.someObject, 'b', 2) |
“Composition API” is only available with version 3.0 and then the “data” property is no longer used in the “options object”, but the data is stored as regular JS variables in the setup() function. In order for that variable to be available outside the Vue instance, ie. within HTML, it is necessary to return it with return in the setup() function.
|
1 2 3 4 5 6 7 |
let app = Vue.createApp({ setup(props, context) { let msg = "Some message" return { msg } } }) let vm = app.mount('#vue_app') |
Reactivity of variable
This variable can now be used within HTML ie. to be displayed through interpolation, however it is still not reactive as a data property. In order for the variable inside the setup() function to have exactly the same properties as some “data” property (ie to be reactive), there are two ways:
a) Reactivity with ref()
The first way is intended for working with primitive data types and it is enough to “do” the value of the variable with the Vue.ref() method:
|
1 |
let msg = Vue.ref("Some message") |
Access to the value of a variable defined in this way within the Vue instance itself is with changes.value, while within HTML it is used without “.value”.
See the Pen
Untitled by Web Programming (@chos)
on CodePen.
b) Reactivity with reactive()
If we have an object, it is necessary to “wrap” it with the Vue.reactive() function. In this case it is not necessary to use .value syntax to get the value of the variable, see example:
See the Pen
Composition API – reactive() by Web programming (@chos)
on CodePen.
“$refs”
As part of the HTML code that is “supervised” by the Vue application, due to the simpler targeting of HTML elements, we can “mark” the desired HTML element. The markup of an HTML element is done by adding the ref attribute within an HTML tag.
|
1 |
ref="some name for recognition" |
for example:
|
1 |
<h4 ref="naslov">Naslov Aplikacije</h4> |
An element marked like this is accessed from a Vue instance with:
|
1 |
this.$refs.nekiNazivZaRaspoznavanje |
The previous example would return the entire HTML element, so if we want the content of that element, we have to additionally access it, e.g.
|
1 |
this.$refs.naslov.innerText |
It should be noted that $refs has a value only after the component has been rendered and that variable is not reactive, so you should avoid using $refs within template or “computed properties”.
Example
See the Pen
Vue $ref by Web Programming (@chos)
on CodePen.
“methods”
Functions related to the Vue instance so-called. “methods” in the “Options API” are represented as functions in the “methods” property, while in the Composition API the functions are in the “setup” property. Methods are most often used when you want something to be executed after an event. It should be emphasized that the “Methods” within the interpolation are executed when loading the instance (component) as well as during every re-rendering of the foreigner. This behavior of methods is made possible by the fact that Vue.js does not take into account what is inside the method, so the method will be recalculated even if the change does not affect the method.
When this data changes, the view will re-render. Method invocation will always run the function whenever a re-render happens.
Vue.js documentation
Example

In this example we have two methods (“printA()” and “printB()”) whose functionality is simple and described by the name of the method itself. However, the functionality that is important in this example is that both methods are executed (shown by the console printout) every time the page is re-rendered. The first thing to pay attention to is the fact that immediately after loading the Vue instance, messages from both methods are printed in the console, which confirms the fact that the methods are executed every time the Vue instance (component) is loaded.
Then you should monitor the console after each click on the action button, because after each click, two new messages are printed, regardless of which button was clicked.
See the Pen Method specificity in Vue.js by Web Programming (@chos) on CodePen.
See the Pen
Composition api methods by Web programming (@chos)
on CodePen.
Conclusion:
With the previous example, we showed that both methods are executed every time the DOM is re-rendered after changing one of the given properties, and even the method that is not affected by the change of the given property, therefore, because of all the aforementioned, it should be emphasized that in the case of frequent user interface updates, there may be problems with the performance of the application, because resources are consumed when restarting all methods. For example, if we have an application that displays a timer that is updated every second, all the functions in the “methods” object will be called to execute after every second, and recalculated regardless of their purpose. In this case, it is recommended to use computed properties.
“computed”
“Computed” properties are an extension of data properties, they also return a value like the given property:
See the Pen
Computed is an extension of the given property by Web Programming (@chos)
on CodePen.
See the Pen
Composition APi – computed by Web programming (@chos)
on CodePen.
From the previous example, it can be seen that “computed properties” are very useful for manipulating already existing data. Since, like data, they always return a value, the name of such a function becomes a property and is used in the application in the same way as we use the “data” property (we do not need to call it as a method). Basically, “computed” properties are variables, whose values depend on other factors andwill not recalculate if dependencies are not changed. Which implies that the function will use its previously calculated (so-called cached) value, as long as there is no dependency change.
Computed properties are not intended to store data, moreover, if a “computed” property returns an object, it will always be a new object, not a modified version of the previous one. “Computed” properties must be functions whose actions must be synchronous and should not have side effects.
When to use Computed properties?
The functions inside the “computed” property are used whenever we have some data that we need to manipulate, transform, filter, and before using it in the template. Use “computed” properties when you want to mutate a property that depends on another property being changed. “Computed” properties should be used as a replacement for inline expressions in the template frame when we have more complex logic.
Some examples of tasks that are good candidates for using “computed” properties are:
- Updating large amounts of information as the user types, such as filtering a list
- Collection of information from “Vuex store”
- Form Validation
- Data visualizations that change depending on what the user needs to see
Example
This example shows the use of the “computed” property for a large set of operations:
|
1 2 3 4 5 6 |
computed: { velikiProracun () { // ... some big calculation that after some time returns the result return 2 } } |
Now we can use the result of these “hard” calculations over and over again within other operations without fear that they will be recalculated if there is no need (ie if they have not changed :
|
1 2 3 4 5 |
methods: { jednostavniProracun (input) { return input * this.velikiProracun } } |
Should use “computed” or “methods” property?
I will try to explain this dilemma through an example in which, although we use different properties, we get the same ultimate functionality.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div id="example"> <p>Originalna poruka: "{{ message }}"</p> <p>Obrnuta poruka: "{{ reversedMessage() }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script> |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div id="example"> <p>Originalna poruka: "{{ message }}"</p> <p>Obrnuta poruka: "{{ reversedMessage }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script> |
The end result is the same, but that doesn’t mean the difference doesn’t exist. The function inside “methods” will be executed every time the page is rendered ie. on every possible DOM change (not only changing the “messages” property), while using the computed property, Vue remembers the value of the property the computed property depends on (messages) and calculates the computed property only if the “dependency” changes, otherwise it returns the cached value.
We conclude:
if the logic of our application has “heavy” calculations, and does not require recalculation of the property on every page rendering, we should use the “computed” property (because we gain performance due to caching). However, if the logic requires recalculation every time the page is rendered, ie. at anychange (not just change dependencies), then use use “methods”.
NOTE:
If the computed property is used within double curly brackets ie. if the interpolation of the JavaScript expression is performed, then only the name of the “computed” property is specified (without the parentheses that indicate the invocation and execution of the function)
eg.
{{ nekoComputedSvojstvo }}
This is another similarity with the “data” property because the “computed” property always returns some value, so practically we expect that prepared (cached) value to be printed instead of interpolated.
Computed property by default has only get-er:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
computed: { fullName() { return this.firstName + ' ' + this.lastName } //ili drugacije napisano: fullName: { get() { return this.firstName + ' ' + this.lastName } } } |
However, they can also provide a setter if needed:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
computed: { fullName: { get() { return this.firstName + ' ' + this.lastName }, set(newValue) { const names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } |
Example
See the Pen
Computed Vue by Web Programming (@chos)
on CodePen.
“watch”
The “watch” property provides an additional level of control, allowing us to monitor changes in the model (data). The functions inside the “watch” object are fired only when a certain property within the given object changes. It should be noted that the “watched” property can track changes on only one property
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName } } }) |
NOTE:
The name of the watcher must be the same as the name of the given property whose change it watches. Through the parameter of the watch function, the changed value of the property that we are “monitoring”
is passed
Deep watch
In order to monitor non-level (nested) properties of an object, we need to set the value of the “deep” parameter to “true”:
|
1 2 3 4 5 6 7 8 |
watch: { nekoSvojstvo: { handler: function () { ... }, deep: true } } |
Composition API has the advantage that it can watch more than one variable, it is allowed to pass them to the watch method as the first parameter, the second parameter is the callback method.
See the Pen
Composition API – watched by Web programming (@chos)
on CodePen.
The callback method has two built-in parameters, so if it fits, they can also be used instead of targeting the monitored variable, seeexample:
|
1 2 3 |
Vue.watch(value, (newValue, oldValue) => { console.log("Nova vresnost je " + newValue + " a stara je: " + oldValue); }); |
And in case two data are tracked as in the previous example:
|
1 2 3 |
Vue.watch([ime, prezime], ([newIme, newPrezime],[oldIme, oldPrezime]) => { punoIme.value = newIme +" " + newPrezime; }); |
When to use the watch property?

“Watch” properties are more specific than computed properties and therefore have a narrower field of action, so they are used less often. Use them when you need to perform some logic after changing a specific child property within the “data” object, where the desired action is:
- asynchronous operation
- calculation of the so-called intermediate result
- further reducing the number of activations of certain operations (e.g. debounce on input event)
In addition to the mentioned cases, we can apply watch for many other functionalities, but it should be carefully evaluated, because although executing some functionality with the “watch” property is feasible, it does not mean that it is recommended, because it can be more complicated than using the “computed” property. The bottom line is that the “watch” property should only be used when the “computed” properties cannot solve your problem.
Example
This example shows a situation where we cannot solve the problem with the “computed” property. One of the reasons for using the “watch” property in this example is to execute an asynchronous operation within it, and another is to define an intermediate result (answer), until the final answer is obtained. Neither of these tasks could be done with the “computed” property.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
new Vue({ el: '#watch-example', data: { question: '', answer: 'I cannot give you an answer until you ask a question!' }, watch: { question: function (newQuestion, oldQuestion) { this.answer = 'Waiting for you to stop typing...' this.nekiAsinhroniZahtev() } }, . . . }) |
Example
In this example, we use the property “searchQuery” with which we monitor the change of the data property of the same name, after which we send an asynchronous request to the server:
See the Pen Watch property for asynchronous request to server by Web Programming (@chos) on CodePen.
Instance configuration
In version 3.0 every Vue application has a configuration object that contains the configuration settings for that application instance:
|
1 2 3 |
const app = createApp({}) app.config = {...} |
This is a global object and can be accessed from any instance or component within the application. These are some of the properties of that configuration global object:
- errorHandler
- warnHandler
- globalProperties can be accessed from any component instance within the application, see example:
123456app.config.globalProperties.foo = 'bar'app.component('child-component', {mounted() {console.log(this.foo) // 'bar'}})
In version 2.0 a global variable could be stored with Vue.prototype
1Vue.prototype.$myGlobalVariable = globalVariable - compilerOptions
- …

