Search code examples
javascripthtmlcustom-element

How to wrap an input field in a custom element?


I am trying to wrap an input field inside a custom element.

The custom element DOM looks like this:

<custom-element>
  <div class="fancy-wrapper">
     <input value="4">
  </div>
<custom-element>

While the element should work like this:

<custom-input id="test"></custom-input>

<script>
let test = document.getElementById('test')
console.log(test.value); //  should return 4 (value of inner input)

test.onkeydown = function(e){
    console.log(e.target.value); // should the new value of the inner input
};
</script>

Is there any way to get the <custom-input> attributes redirected to the <input> attributes inside it, without connecting everything by hand?


Solution

  • No, it is no different than having one DIV and another child DIV

    You have to make the connection between the CustomElement and content yourself.

    One way is to define a Get/Set function on your Custom-Element that fetches the value of a child input

    Instead of manually declaring Get/Set You can ofcourse loop any child element and assign on the CustomElement with defineProperty or Proxies

    Example below creates 2 INPUT fields and a this.input array:

        <number-and-range>
           <input type="number"> // this.input[0]
           <input type="range">  // this.input[1]
        </number-and-range>
    

    And connects (GET/SET) <number-and.range>.value to this.input[0]

    customElements.define('number-and-range', class extends HTMLElement {
      get value() {
        return this.input[0].value;
      }
    
      set value(val) {
        //input validation should go here
        this.input[0].value = val;
        console.clear();
        console.log('new value:',val);
      }
      connectedCallback() {
        this.input = ['number', 'range'] //create [0] and [1] values in array
          .map((type, idx) => Object.assign(
            this.appendChild(document.createElement('input')), {
              type,
              min: 20,
              max: 50,
              oninput: _ => this.value = this.input[~~!idx].value = this.input[idx].value //toggle [0] and [1]
            }));
        this.value = 42;//default value
      }
    });
    
    let el=document.querySelector('number-and-range');
    console.log(el.value);
    el.value=99;
    <body>
    <h3>Custom Element : Connected INPUT and Range slider</h3>
    Please enter a number between 20 and 50, or use the range slider
    <p>
    <number-and-range></number-and-range>
    </p>
    </body>