Vanilla Two-Way Binding in JavaScript
You don’t need external libraries to bind data
Nowadays, we have an enormous amount of tools on the front end to resolve the different issues that we may face. This is great in many ways, primarily because you don’t have to reinvent the wheel every time.
But it also has some really bad consequences. One of them is the situation where developers know how to use the tools but have no idea what JavaScript is actually doing behind the scenes. As a front-end developer, we have the obligation to know as much as we can about JS. That knowledge is going to allow you to easily understand what and how any library or framework works and is going to help you resolve any complicated issue that you may run into.
It’s OK to use tools, but you have to ask yourself, “Can I implement this from scratch?”
If the answer is yes, then go ahead and use any already implemented functionality. But if the answer is no, then you should at least try to understand what is actually happening.
While thinking about all of this, I decided to start implementing and blogging some of the most common features that all of these new — and not so new — frameworks and libraries have.
The Objective
We are going to create a simple two-way binding implementation using vanilla script (ES5).
Part 1: HTML Approach
In the HTML, we are going to use a custom attribute called data-tw-bind that’s going to receive the name of the property to bind.
This is going to allow us to select the elements that we need from the DOM and to which property they are going to be bound.
Part 2: JS Implementation
From the HTML, we are going to select:
- Which elements are going to work with two-way binding.
- Which props are going to be added to the scope of our app.
Any change on these props by code is going to update the elements in the DOM bound to that prop, and any change to these props in the DOM is going to change the bound prop in the scope.
Getting the elements and setting an initial scope
So the first thing our app is going to do is get all the elements with the custom attribute data-tw-bind set.
Next, we are going to iterate on those elements, get the property name, and for those of type text and textarea— our implementation is going to handle only those two, but adding others should be quite simple — we are going to add a listener to the onkeyup event. In the listener, we are going to set the value of the scope prop to the element value.
So far, we don’t have anything working yet. We need to find a way to change the DOM when the scope prop changes.
Adding properties to the scope with a set and get function
This is the approach I decided to take. When setting a scope property, a set function is going to be executed that also updates the DOM in the proper places.
Wait… what? Let’s see the code:
We have all the same stuff that we had before with a bunch of new things. Before setting the listeners on the onkeyup event, we are calling a function called addScopeProp that does a bunch of things. Let’s go through them:
- It receives the prop name as a parameter.
- It checks if the scope has already set the prop.
- It declares a variable value that is going to be populated with the new value on the set callback.
- Then it calls the function
definePropertyof Object with the scope, the new prop to add, and the definition that is going to set a couple of things. - In the set callback, we have a function that receives the new value, populates the value variable, and then iterates through the elements to see which of them are bound to that property. For those that are bound, it sets their value to the new value of the property.
- In the get callback, it returns the content of the value variable.
- Finally, to allow iterating through them, we need to set enumerable to
true.
And that’s it. That’s all that it takes to create a simple two-way binding using vanilla script. Of course, this is the approach that I take. There are other ways to resolve this, but I really enjoy doing this one.
The full code can be seen on GitHub.
Conclusion
As you can see, implementing a two-way binding is not that difficult and it is great to be able to do it by yourself.
Use tools, but don’t forget that the magic is not in knowing them but in knowing how they actually work!

