Multiple input elements controlling a reactive variable

What is the idiomatic way of having two input elements both showing the value of the same variable and controlling it? E.g. a number that can be set both on a range slider and on a numeric input field, while both are reflecting its value.

I tried so far:

viewof number = html`<input type="range">`
html`<input type="number" value="${number}"/>`

…but the number input only displays the value, does not control it.

Moreover, it would be great if there was a way to formulate this as a “component”, i.e. reusable in other contexts (maybe as a function?)

Thank you in advance!

Combine the two inputs into a cell, and then use input event listeners to coordinate changes between them. The input events will bubble up so that viewof will respond to interaction on either input. You just need to set element.value on the element returned by the cell so that the desired value is exposed to other cells in the notebook.

Here’s some code:

viewof x = {
  const div = html`
    <input type=range min=0 max=100>
    <input type=number min=0 max=100 style="width:auto;">
  `;
  const range = div.querySelector("[type=range]");
  const number = div.querySelector("[type=number]");
  div.value = range.value = number.value = 50;
  range.addEventListener("input", () => number.value = div.value = range.valueAsNumber);
  number.addEventListener("input", () => range.value = div.value = number.valueAsNumber);
  return div;
}

And here’s a live demo: https://beta.observablehq.com/@mbostock/linked-inputs

3 Likes

Wow, thank you very much for the quick and comprehensive answer!