If I was going to sum up my experiences with Vue in a sentence, I’d probably say something like “it’s just so reasonable” or “It gives me the tools I want when I want them, and never gets in my way”. Again and again, when learning Vue, I smiled to myself. It just made sense, elegantly.
This is my own introductory take on Vue. It’s the article I wish I had when I was first learning Vue. If you’d like a more non-partisan approach, please visit Vue’s very well thought out and easy to follow Guide.

Article Series:
- Rendering, Directives, and Events (You are here!)
- Components, Props, and Slots
- Vue-cli
- Vuex
- Animations
One of my favorite things about Vue is that it takes all of the successful things from other frameworks, and incorporates them without getting disorganized. Some examples that stand out for me:
- A virtual DOM with reactive components that offer the View layer only, props and a Redux-like store similar to React.
- Conditional rendering, and services, similar to Angular.
- Inspired by Polymer in part in terms of simplicity and performance, Vue offers a similar development style as HTML, styles, and JavaScript are composed in tandem.
Some benefits I’ve enjoyed over Vue’s competitors: cleaner, more semantic API offerings, slightly better performance than React, no use of polyfills like Polymer, and an isolated, less opinionated view than Angular, which is an MVC.
I could go on, but it’s probably better if you read their comprehensive and community-driven comparison with other frameworks. It’s worth a read, but you can skip back to it later if you’d like to dive into the code.
Let’s Get Started!
We can’t kick this off without the obligatory “Hello, world!” example. Let’s do that so you can get up and running:
<div id="app">
{{ text }} Nice to meet Vue.
</div>
new Vue({
el: '#app',
data: {
text: 'Hello World!'
}
});
See the Pen Vue Hello World by Sarah Drasner (@sdras) on CodePen.
If you’re familiar with React, this will have some similarities. We’ve escaped into JavaScript in the middle of the content with the mustache template and used a variable, but one difference is we are working with straight up HTML instead of JSX. JSX is pretty easy to work with, but I do think it’s nice that I don’t have to spend time changing class
to className
, etc. You’ll also notice that this is pretty lightweight to get up and running.
Now let’s try Vue out with something I really love: loops and conditional rendering.
Conditional Rendering
Let’s say I have a set of items, like navigation, that I know I’m going to reuse. It might make sense to put it in an array to update it in a few places dynamically and consistently. In vanilla JS (with Babel) we might do something like this: create the array, then create an empty string where we add each item wrapped in an <li>
, and then wrap all of that in a <ul>
and add it to the DOM with innerHTML:
<div id="container"></div>
const items = [
'thingie',
'another thingie',
'lots of stuff',
'yadda yadda'
];
function listOfStuff() {
let full_list = '';
for (let i = 0; i < items.length; i++) {
full_list = full_list + `<li> ${items[i]} </li>`
}
const contain = document.querySelector('#container');
contain.innerHTML = `<ul> ${full_list} </ul>`;
}
listOfStuff();
See the Pen e699f60b79b90a35401cc2bcbc588159 by Sarah Drasner (@sdras) on CodePen.
This works fine, but it’s a bit messy for something so standard. Now let’s implement that same thing with Vue’s loop with v-for
:
<div id="app">
<ul>
<li v-for="item in items">
{{ item }}
</li>
</ul>
</div>
const app4 = new Vue({
el: '#app',
data: {
items: [
'thingie',
'another thingie',
'lots of stuff',
'yadda yadda'
]
}
});
See the Pen Conditional Rendering in Vue by Sarah Drasner (@sdras) on CodePen.
Pretty clean and declarative. If you’re familiar with Angular, this will likely be familiar to you. I find this to be such a clean and legible way to conditionally render. If you jumped into the code and had to update it, you could do so very easily.
Another really nice offering is dynamic binding with v-model. Check this out:
<div id="app">
<h3>Type here:</h3>
<textarea v-model="message" class="message" rows="5" maxlength="72"></textarea><br>
<p class="booktext">{{ message }} </p>
</div>
new Vue({
el: '#app',
data() {
return {
message: 'This is a good place to type things.'
}
}
});
See the Pen Vue Book v-model basic by Sarah Drasner (@sdras) on CodePen.
You’ll probably notice two things about this demo. First, that it really took nothing at all to type directly into the book and dynamically update the text. Vue enables us to very easily set up two-way binding between the <textarea>
and the <p>
with v-model
.
The other thing you might notice is that we’re now putting data in a function. In this example, it would work without doing so. We could have just put it in an object like our earlier examples. But this would only work for the Vue instance and be exactly the same across the application (thus, not so great for individual components). It’s OK for one Vue instance, but this will share data across all of the child components as well. It’s good practice to start putting data in a function because we’ll need to when we start using components and want them to each hold state of their own.
These aren’t the only easy input bindings available to you at all, and even v-if
has an alternate, v-show
, which won’t mount/unmount the component, but rather, leave it in the DOM and toggle visibility.
There are so many more directives available to you, here’s a sampling of some of the ones I use very often. A lot of these offer shortcuts as well, so I’ll show both. From here on, we’ll mostly use the shortcuts, so it’s good to at least familiarize yourself with them a little bit in this table.
Name | Shortcut | Purpose | Example |
---|---|---|---|
v-if, v-else-if, v-else |
none | Conditional Rendering | <g v-if="flourish === 'A'"></g> |
v-bind |
: | Bind attributes dynamically, or pass props | <div :style="{ background: color }"></div> |
v-on |
@ | Attaches an event listener to the element | <button @click="fnName"></button> |
v-model |
none | Creates two-way binding | <textarea rows="5" v-model="message" maxlength="72"></textarea> |
v-pre |
none | Skip compiling for raw content, can boost performance | <div v-pre>{{ raw content with no methods}}</div> |
v-once |
none | Don’t rerender | <div class="v-once">Keep me from rerendering</div> |
v-show |
none | Will show or hide a component/element based on state, but will leave it in the DOM without unmounting (unlike v-if) | <child v-show="showComponent"></child> (toggles visibility when showComponent is true) |
There are also really nice event modifiers and other API offerings to speed up development like:
@mousemove.stop
is comparable toe.stopPropogation()
@mousemove.prevent
this is likee.preventDefault()
@submit.prevent
this will no longer reload the page on submission@click.once
not to be confused with v-once, this click event will be triggered once.v-model.lazy
won’t populate the content automatically, it will wait to bind until an event happens.
You can even configure your own keycodes.
We’ll use these in examples a bit more coming up!
Event Handling
Binding that data is all well and good but only gets us so far without event handling, so let’s cover that next! This is one of my favorite parts. We’ll use the binding and listeners above to listen to DOM events.
There are a few different ways to create usable methods within our application. Just like in vanilla JS, you can pick your function names, but methods are intuitively called, well, methods!
new Vue({
el: '#app',
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++;
}
}
});
<div id="app">
<p><button @click="increment">+</button> {{ counter }}</p>
</div>
We’re creating a method called increment
, and you can see that this automatically binds to this
and will refer to the data in this instance and component. I love this kind of automatic binding, it’s so nice to not have to console.log
to see what this
is referring to. We’re using shorthand @click
to bind to the click event here.
Methods aren’t the only way to create a custom function. You can also use watch
. The main difference is that methods are good for small, synchronous calculations, while watch
is helpful with more tasking or asynchronous or expensive operations in response to changing data. I tend to use watch most often with animations.
Let’s go a little further and see how we’d pass in the event itself and do some dynamic style bindings. If you recall in the table above, instead of writing v-bind
, you can use the shortcut :
, so we can bind pretty easily to style (as well as other attributes) by using :style
and passing in state, or :class
. There are truly a lot of uses for this kind of binding.
In the example below, we’re using hsl()
, in which hue calculated as a circle of degrees of color that wraps all the way around. This is good for our use as it will never fail, so as we track our mouse in pixels across the screen, the background style will update accordingly. We’re using ES6 template literals here.
new Vue({
el: '#app',
data() {
return {
counter: 0,
x: 0
}
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
},
xCoordinate(e) {
this.x = e.clientX;
}
}
});
<div id="app" :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }" @mousemove="xCoordinate">
<p><button @click="increment">+</button> {{ counter }} <button @click="decrement">-</button></p>
<p>Pixels across: {{ x }}</p>
</div>
See the Pen Showing simple event handling by Sarah Drasner (@sdras) on CodePen.
You can see that we didn’t even need to pass in the event to the @mousemove
handler, Vue will automatically pass it for you to be available as a parameter for the method. (shown as e
here).
Also, native methods can also be used, such as event.clientX
, and it’s simple to pair them with this
instances. In the style binding on the element there’s camel casing for hyphenated CSS properties. In this example, you can see how simple and declarative Vue is to work with.
We don’t even actually need to create a method at all, we could also increase the counter directly inline in the component if the event is simple enough:
<div id="app">
<div class="item">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/backpack.jpg" width="235" height="300"/>
<div class="quantity">
<button class="inc" @click="counter > 0 ? counter -= 1 : 0">-</button>
<span class="quant-text">Quantity: {{ counter }}</span>
<button class="inc" @click="counter += 1">+</button>
</div>
<button class="submit" @click="">Submit</button>
</div><!--item-->
</div>
new Vue({
el: '#app',
data() {
return {
counter: 0
}
}
});
See the Pen Backpack Shop Counter by Sarah Drasner (@sdras) on CodePen.
You can see that we’re updating the state directly in the @click
handler without a method at all- you can also see that we can add a little bit of logic in there as well (as you wouldn’t have lower than zero items on a shopping site). Once this logic gets too complex, though, you sacrifice legibility, so it’s good to move it into a method. It’s nice to have the option for either, though.
Article Series:
- Rendering, Directives, and Events (You are here!)
- Components, Props, and Slots
- Vue-cli
- Vuex
- Animations
Nowadays..lot’s of frameworks released..so it’s really hard to pick which is better to learn? which is easy to learn?angular/react or vue? any suggestion would be great..
Hi there!
You just asked the eternal question! I think it really depends on your needs, and the first section of the article aims to answer that a bit. But that said, I would say if you’re looking for a full MVC, Angular 2 is a really great choice (Vue and React are the View layer only). If you’re looking for something with an outstanding community, React is amazing. And if you want something with a lot of power but is elegant in its legibility and simplicity, Vue is pretty incredible. That said, everyone will give you a different answer to this question, so it’s nice to check out Todo.mvc which compares each in code, or try each out a little before you make the production investment. Hope that helps!
wow,cool
Great talk about the beloved Vue.js, keep going, please…
Thank you! More tomorrow! And every day this week :)
Awesome! Especially looking forward to the Animations article. Cool beans!
Hi Sarah, what projects have you built using Vue? Could you provide some links? Thanks!
Looking forward to your next post.
Hey Lars!
I have a couple sample repos on my github profile, which we’ll use for examples in subsequent posts, which will provide more detail for real-life build processes.
https://github.com/sdras/vue-wine-label
https://github.com/sdras/vue-weather-notifier
All of my other work with Vue is proprietary and can’t be released, so hopefully these examples and other posts are helpful.
I really like Vue’s pragmatic approach – very simple to get started with and connect with other libraries and tooling, and all without being overly-prescriptive. This makes it easy to add Vue to existing projects without needing to do major code rewrites.
I agree!
Great intro! It was really helpful. In your hue saturation example, you were able to access your ‘x’ just by putting it in a template literal ${x}, instead of using the moustache {{ }}. Is that because the :bind method automatically gets access to all the items inside the data function?
For your Event Handling code sample, you are just missing one ‘}’ to close the methods obj.
Thanks
Hey Alex!
I’m glad you found it helpful. Yep you got it, the :style attribute I used was using the shorthand for v-bind so I was able to access the state. You can double check this by simply changing :style to style, and the hsla background no longer works. Thanks for catching my typo! Fixed.
Really excellent intro! For people who love and talks Spanish I wrote a similar post at https://www.jaimeolmo.com/2016/02/primeros-pasos-usando-vue-js/
Cheers!
Very nice. Thanks!
Is vue suitable for multipage(say 10 pages/tabs) apps with 5-15 components per page? Does the complexity grow exponentially?
Yep, it sure does! We’re starting off small here for clarity. In future articles we’ll discuss actual builds with some examples as well as Vuex for more complex state management.
Thats my first frame work and Vue looks way easier to learn against React and Angular.
A question about eventhandler @mousemove? why Vue documentation doesn’t mention anything about that? :( I’ve been searching for it for a while…
Nice job btw, waiting for the rest ^^
Hey Can – about @mousemove basically with Vue events you can use any vanilla JavaScript DOM event name, so all the usuals will work as long as you replace ‘on’ with ‘@’.
e.g. onmousemove –> @mousemove
onkeydown –> @keydown
onblur –> @blur
and so on…
Holly Molly dont say we can use any js event handling with @? xD got hit QQ
Thanks, exactly like you wrote:
great article :)
I really drank the Vue water when looking to migrate an application from Angular 1 — but Angular 2 didn’t really suit my [existing] workflow. There was something sort of attractive about the ease of learning Vue, as well as its best-of-both-worlds vibe. I’m kind of rooting for it, so I’m geeked to see you guide the Sauron’s Eye of CSS-Tricks in its direction.
That sounds super ominous but let’s pretend the light of Sauron’s Eye is warm and comforting.
Thanks for the great article. And also there is seems to be a typo in the string ‘@mousemove.prevent this is like e.preventDelegation()’
Must be preventDefault i guess?
haha oops sorry about the typo, it’s fixed now, thank you!
Best intro to Vue.js I’ve read so far. Very very nice. Thanks!
Hi Sarah,
You missing something to demonstrate on this event part.
On how to make custom event on standalone custom components
The:
1. this.$emit(‘custom-name-of-event’, data)
2. this.$dispatch(‘custom-name-of-event’, data)
3. this.$broadcast(‘custom-name-of-event’, data)
Nice article!
Excellent point! That would probably belong in the section when we move over to real components in section 3, but you’re totally right, I neglected to cover that. After I’m done putting the series out, I’ll make a revision and include it. Thanks for reminding me.
Hi Sarah, seems like you have worked with Vue and Angular a bit. I would like to get your opinion on whether Vue js is ideal for large scale applications (context: an application with java on the backend and requiring calls/requests to RESTful API services)
I do think it’s great for large scale applications, particularly because “it stood on the shoulders” of other alternatives such as Angular and React, such as the inclusion of Vuex, which offers a Redux-like state management library, which I think is pretty important for managing an application with a lot of state.
Regarding $broadcast, $dispatch – I believe they’ve been deprecated in Vue2
https://github.com/vuejs/vue/issues/2873
This is a great intro to Vue.js. It’s strange that Vue does not get as much press as React or Angular, probably because it is not backed by the two Internet giants. I would argue that Vue provides a much better alternative to React when migrating off of Backbone apps.