I've been reading up on web components and am pretty intrigued by the nascent spec. Does anyone know if there is any support for 2-way data binding in the DOM, without having to use Polymer? An example would be appreciated.
-
You can give [Slim.js](http://slimjs.com/#/getting-started) a try. I'm not a big fan. I'm still looking for a nice soluition around the problem while avoiding any library (I'm tired to learn one DSL after another). So far my approach has been `init()` with template strings and `update()`, old fashion, similar to D3 charts. – Adrian Moisa Dec 04 '17 at 11:33
4 Answers
Object.observe is a potential new way to do databinding in javascript. This feature is scheduled for Ecmascript 7(javascript), but some browsers currently support it, check here. Also check out this html5rocks article on object.observe

- 2,857
- 6
- 34
- 60
-
14
-
1Shame that Object.observe was deprecated...having to create a separate object (proxy), while very useful for its own reasons, is not the same thing and doesn't offer all the same benefits. Nontheless it seems there were good reasons for deprecating it: https://www.infoq.com/news/2015/11/object-observe-withdrawn – Matt Browne Jun 10 '16 at 11:59
No, data binding isn't part of the Web Components spec.
You can of course implement data binding yourself using native JavaScript event listeners, and possibly the Proxy object, but it's probably best not to re-invent the wheel: if you want data binding, choose one of the many JavaScript frameworks out there which supports that. Polymer, React, Angular, and Vue are some recent examples of such libraries.

- 45,670
- 22
- 127
- 172
-
2I don't agree with this. For a simple use case, you don't need to adopt libraries and the npm house of cards. Web components can be a simple way to go in trivial situations. – Jeff Putz Apr 23 '22 at 01:11
I've been playing around with this over the last few days. You can create a StateObserver class, and extend your web components from that. A minimal implementation looks something like this:
// create a base class to handle state
class StateObserver extends HTMLElement {
constructor () {
super()
StateObserver.instances.push(this)
}
stateUpdate (update) {
StateObserver.lastState = StateObserver.state
StateObserver.state = update
StateObserver.instances.forEach((i) => {
if (!i.onStateUpdate) return
i.onStateUpdate(update, StateObserver.lastState)
})
}
}
StateObserver.instances = []
StateObserver.state = {}
StateObserver.lastState = {}
// create a web component which will react to state changes
class CustomReactive extends StateObserver {
onStateUpdate (state, lastState) {
if (state.someProp === lastState.someProp) return
this.innerHTML = `input is: ${state.someProp}`
}
}
customElements.define('custom-reactive', CustomReactive)
class CustomObserved extends StateObserver {
connectedCallback () {
this.querySelector('input').addEventListener('input', (e) => {
this.stateUpdate({ someProp: e.target.value })
})
}
}
customElements.define('custom-observed', CustomObserved)
<custom-observed>
<input>
</custom-observed>
<br />
<custom-reactive></custom-reactive>
I like this approach because it occurs directly between precisely those elements you want to communicate with, no dom traversal to find data-
properties or whatever.
-
How would this allow communication with other components? By making them inherit from the same StateObserver class? I’m assuming you would create a class like this for every set of components that need to communicate with each other? – Jeremy Cantrell Feb 23 '23 at 18:46
-
@JeremyCantrell yes, inherit from the StateObserver in order to observe state. You could create separate classes for groups of components but the usual pattern would be to have all components observing the same state. Each observing component just returns early if a change is not relevant to it as in `if (state.someProp === lastState.someProp) return` – Mr5o1 Feb 26 '23 at 22:49
One way: $0.model = {data};
setter on $0 assigns $0.data, responding to the update, and the other way: $1.dispatchEvent(new CustomEvent('example', {detail: $1.data, cancelable: true, composed: true, bubbles: true}));
with $0.addEventListenever('example', handler)
gives 2 way data binding. The data object is the same, shared on 2 elements, events and setters allow responding to updates. To intercept updates to an object a Proxy works model = new Proxy(data, {set: function(data, key, value){ data[key] = value; ...respond... return true; }})
or other techniques. This addresses simple scenarios. You might also consider looking at and reading the source for Redux, it provides conventions that seem relatively popular. As Ajedi32 mentions reinventing the wheel for more complex scenarios is not so practical, unless it's an academic interest.

- 2,304
- 1
- 27
- 29