<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Component Example</title>
</head>
<body>
<form action="#">
<input type="number" name="cvv" placeholder="Enter CVV Number">
<popup-info img="./info-circle.svg"
data-text="Your card validation code (CVC) is an extra security feature — it is the last 3 or 4 numbers on the back of your card.">
</popup-info>
</form>
<script>
class PopUpInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
// Create a shadow root
this.attachShadow({ mode: 'open' }); // sets and returns 'this.shadowRoot'
// Create (nested) span elements
const wrapper = document.createElement('span');
wrapper.setAttribute('class', 'wrapper');
const icon = wrapper.appendChild(document.createElement('span'));
icon.setAttribute('class', 'icon');
icon.setAttribute('tabindex', 0);
// Insert icon from defined attribute or default icon
const img = icon.appendChild(document.createElement('img'));
img.src = this.hasAttribute('img') ? this.getAttribute('img') : './info-circle.svg';
const info = wrapper.appendChild(document.createElement('span'));
info.setAttribute('class', 'info');
// Take attribute content and put it inside the info span
info.textContent = this.getAttribute('data-text');
// Create some CSS to apply to the shadow DOM
const style = document.createElement('style');
style.textContent = '.wrapper {position: relative;}.info { font-size: 0.8rem; width: 200px; display: inline-block; border: 1px solid black; padding: 10px; background: white; border-radius: 10px; opacity: 0; transition: 0.6s all; position: absolute; bottom: -60px; left: 10px; z-index: 3;}img {width: 1.2rem;}.icon:hover + .info, .icon:focus + .info {opacity: 1;}';
// attach the created elements to the shadow DOM
this.shadowRoot.append(style, wrapper);
}
}
customElements.define('popup-info', PopUpInfo);
</script>
</body>
</html>