0

I am currently working on web components which use JQuery (3.6.3) and materialize (1.0)

The labels of the materialize components do not work in shadowRoot for some reason. Instead of moving above the input, they just stay at their initial position and overlap the actual input.

Here is basically what i am trying to achieve in shadowRoot:

<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"/>
<body>
    <div class="input-field">
      <input id="email" type="email">
      <label for="email">Email</label>
    </div>
</body>
</html>

And my shadowRoot basically looks like this:

const jquery = document.createElement("script"); 
jquery.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"; 

const materializeJS = document.createElement("script"); 
materializeJS.src = "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"; 

const materializeCss = document.createElement("link"); 
materializeCss.rel = "stylesheet"; 
materializeCss.href ="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css";
   
class MElement extends HTMLElement {
 constructor(tagName) {
   super();
   let component = this;
   $(document).ready(function () {
    component.attachShadow({mode: 'open', delegatesFocus: true }); 
    component.shadowRoot.innerHTML = component.innerHTML;
    component.shadowRoot.appendChild(jquery); 
    component.shadowRoot.appendChild(materializeJS); 
    component.shadowRoot.appendChild(materializeCss); 
   });
 }
}
window.customElements.define("m-element", MElement);
<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<body>
  <m-element>
    <div class="input-field">
      <input id="email" type="email">
      <label for="email">Email</label>
    </div>
  </m-element>
</body>
</html>

The current solution: I actually fixed it, by adding a custom initializer and delegating the focus. But i feel like this solution is kinda dirty and I'm still hoping for a suggestion on a clean solution...

const jquery = document.createElement("script"); 
jquery.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"; 

const materializeJS = document.createElement("script"); 
materializeJS.src = "https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/js/materialize.min.js"; 

const materializeCss = document.createElement("link"); 
materializeCss.rel = "stylesheet"; 
materializeCss.href ="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css";
   
class MElement extends HTMLElement {
    constructor(tagName) {
       super();
       let component = this;
       $(document).ready(function () {
        component.attachShadow({mode: 'open', delegatesFocus: true }); 
        component.shadowRoot.innerHTML = component.innerHTML;
        component.shadowRoot.appendChild(jquery); 
        component.shadowRoot.appendChild(materializeJS); 
        component.shadowRoot.appendChild(materializeCss); 
        component.initFields();  
       });
       window.me = component
    } 
    
    initFields()
    {
        let fields = this.shadowRoot.querySelectorAll(".input-field");
        for (let f = 0; f < fields.length; f++) {
            let inputs = fields[f].querySelectorAll("input");
            for (var i = 0; i < inputs.length; i++) {
                let input = inputs[i]; 
                if (input)
                {
                    input.classList.add("active");
                    let label = null;
                    if (input.id)
                    {
                        label = fields[f].querySelector(`label[for="${input.id}"]`);
                    }

                    let updateFields = function () {
                        if ($(input).is(':focus')
                        || input.autofocus
                        || input.value != null && input.value.length > 0
                        || input.placeholder != null && input.placeholder.length > 0) {

                            fields[f].classList.add("active");
                            input.classList.add("active");
                            if (label) label.classList.add("active");
                        }
                        else {
                            fields[f].classList.remove("active");
                            input.classList.remove("active");
                            if (label) label.classList.remove("active");
                        }
                    };

                    $(input).on("focus", updateFields);
                    $(input).on("blur", updateFields);
                    updateFields();
                }
            }
        }
    }
}

window.customElements.define("m-element", MElement); 
<!DOCTYPE html>

<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<body>
  <m-element>
    <div class="input-field">
      <input id="firstname">
      <label for="firstname">First Name</label>
    </div>
    
    <div class="input-field">
      <input id="lastname" placeholder="Enter your last name">
      <label for="lastname">Last Name</label>
    </div>
  </m-element>
</body>
</html>

Here's all i already tried, that definately didn't work:

  1. Set shadowRoot.delegatesFocus to true, without adding the "initFields" fix.
  2. Call "M.updateTextFields();". This actually cannot work in this version of materialize, because materialize queries from the document instead of the shadowRoot. The updateFields delegate in the fix i wrote actually has the same condition as the original updateTextFields method.
Canabale
  • 157
  • 1
  • 7

0 Answers0