{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/web-component-javascript/",
    "result": {"data":{"site":{"siteMetadata":{"title":"CrewCode Solutions"}},"markdownRemark":{"id":"d4aefb01-f69c-5a6f-a0de-824fe424b563","excerpt":"In this article iam gonna explain you how you can create custom web component in javascript i will demonstrate you popup modal example for this\nWeb component is…","html":"<p>In this article iam gonna explain you how you can create custom web component in javascript i will demonstrate you popup modal example for this\nWeb component is html element which you can configure as you want behind the scene it uses native html element</p>\n<p><strong><em>Why web component</em></strong></p>\n<ul>\n<li>\n<p>Encapsulate Logic + UI</p>\n</li>\n<li>\n<p>Reusable across pages</p>\n</li>\n</ul>\n<p><strong><em>Tools for web component or custom html element</em></strong></p>\n<ul>\n<li>\n<p>Custom HTML Element:\nRegister your own html tag</p>\n</li>\n<li>\n<p>Shadow Dom:\nManage a separate DOM node tree for your html element</p>\n</li>\n<li>\n<p>Template and Slots:\nWrite Html templates that you can add to your html element</p>\n</li>\n</ul>\n<p><strong>_ Ways for creating custom elements _</strong></p>\n<ul>\n<li>\n<p>Autonomous Elements: These are the custom html element which doesn't depend upon anything means not on native html element</p>\n</li>\n<li>\n<p>Extended Built-In elements: You can create custom element by extending built in html element</p>\n</li>\n</ul>\n<p><strong><em>Web component lifecycle</em></strong></p>\n<ul>\n<li>\n<p>constructor() -> Baic initializations, Element created</p>\n</li>\n<li>\n<p>connectedCallback() -> DOM Initializations, Element attached to dom</p>\n</li>\n<li>\n<p>disconnectedCallback() -> Cleanup work, Element detached from dom</p>\n</li>\n<li>\n<p>attributeChangedCallback() -> Observed Attribute updated, Update Data + DOM</p>\n</li>\n</ul>\n<h4>Step 1 Create a folder and files for our modal component</h4>\n<p>Create a folder with the name it's depend upon you and create two file named <strong><em>modal.js</em></strong> and <strong><em>index.html</em></strong> again the name of javascript file depends upon you</p>\n<ul>\n<li>Inside modal.js file create a class for the web component and extend the class with HTMLElement and register your custom html element</li>\n</ul>\n<pre><code class=\"language-js\">class Modal extends HTMLElement {}\n\n//registering custom element named as uc-modal\ncustomElement.define(\"uc-modal\", Modal);\n</code></pre>\n<ul>\n<li>Go to <strong><em>index.html</em></strong> file and call the modal.js file and our custom html element which we have registered above</li>\n</ul>\n<pre><code class=\"language-html\">&#x3C;!DOCTYPE html>\n&#x3C;html lang=\"en\">\n  &#x3C;head>\n    &#x3C;meta charset=\"UTF-8\" />\n    &#x3C;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    &#x3C;meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n    &#x3C;title>Web Components&#x3C;/title>\n    &#x3C;style>\n      * {\n        box-sizing: border-box;\n      }\n\n      body {\n        margin: 2rem;\n        font-family: sans-serif;\n      }\n    &#x3C;/style>\n    &#x3C;script src=\"modal.js\">&#x3C;/script>\n  &#x3C;/head>\n  &#x3C;body>\n    &#x3C;uc-modal>&#x3C;/uc-modal>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre>\n<h4>Step 2 Adding templates for our Web component using Shadow Dom</h4>\n<p>As i have explained in the begining of this article that shadow dom manage dom tree for our html element so that it doesn't interfare with the dom tree outside our web component</p>\n<p>And we need to update our web component code to the following</p>\n<pre><code class=\"language-js\">class Modal extends HTMLElement {\n  constructor() {\n    super();\n    //registering the shadow dom\n    this.attachShadow({ mode: \"open\" });\n    this.isOpen = false;\n\n    //template for our modal with slot to take content from outside this web component\n    this.shadowRoot.innerHTML = `\n        &#x3C;style>\n            #backdrop {\n                position: fixed;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100vh;\n                background: rgba(0,0,0,0.75);\n                z-index: 10;\n                opacity: 0;\n                pointer-events: none;\n            }\n\n            :host([opened]) #backdrop,\n            :host([opened]) #modal {\n                opacity: 1;\n                pointer-events: all;\n            }\n\n            :host([opened]) #modal {\n                top: 15vh;\n            }\n\n            #modal {\n                position: fixed;\n                top: 10vh;\n                left: 25%;\n                width: 50%;\n                z-index: 100;\n                background: white;\n                border-radius: 3px;\n                box-shadow: 0 2px 8px rgba(0,0,0,0.26);\n                display: flex;\n                flex-direction: column;\n                justify-content: space-between;\n                opacity: 0;\n                pointer-events: none;\n                transition: all 0.3s ease-out;\n            }\n\n            header {\n                padding: 1rem;\n                border-bottom: 1px solid #ccc;\n            }\n\n            ::slotted(h1) {\n                font-size: 1.25rem;\n                margin: 0;\n            }\n\n            #main {\n                padding: 1rem;\n            }\n\n            #actions {\n                border-top: 1px solid #ccc;\n                padding: 1rem;\n                display: flex;\n                justify-content: flex-end;\n            }\n\n            #actions button {\n                margin: 0 0.25rem;\n            }\n        &#x3C;/style>\n        &#x3C;div id=\"backdrop\">&#x3C;/div>\n        &#x3C;div id=\"modal\">\n            &#x3C;header>\n                &#x3C;slot name=\"title\">Please Confirm Payment&#x3C;/slot>\n            &#x3C;/header>\n            &#x3C;section id=\"main\">\n                &#x3C;slot>&#x3C;/slot>\n            &#x3C;/section>\n            &#x3C;section id=\"actions\">\n                &#x3C;button id=\"cancel-btn\">Cancel&#x3C;/button>\n                &#x3C;button id=\"confirm-btn\">Okay&#x3C;/button>\n            &#x3C;/section>\n        &#x3C;/div>\n    `;\n  }\n}\n\n//registering custom element named as uc-modal\ncustomElement.define(\"uc-modal\", Modal);\n</code></pre>\n<h4>Step 3 Adding logics to our Web component to open the modal</h4>\n<p>We need to open and close our modal which will be controlled by outside our web component by those who will be calling this\nweb component</p>\n<ul>\n<li>\n<p>We need to update our modal.js and add code logic to open and close the modal for this we will be adding method attributeChangedCallback which is web component lifecycle which always run if there is anything changed on our shadow dom</p>\n</li>\n<li>\n<p>We will be adding method observedAttributes which is static method which returns what attribute has changed</p>\n</li>\n<li>\n<p>We will be adding open method which will change the web component attribute that is uc-model and add opened attribute and this method will be called from outside the web component</p>\n</li>\n</ul>\n<pre><code class=\"language-js\">class Modal extends HTMLElement {\n  constructor() {\n    super();\n    //registering the shadow dom\n    this.attachShadow({ mode: \"open\" });\n    this.isOpen = false;\n\n    //template for our modal with slot to take content from outside this web component\n    this.shadowRoot.innerHTML = `\n        &#x3C;style>\n            #backdrop {\n                position: fixed;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100vh;\n                background: rgba(0,0,0,0.75);\n                z-index: 10;\n                opacity: 0;\n                pointer-events: none;\n            }\n\n            :host([opened]) #backdrop,\n            :host([opened]) #modal {\n                opacity: 1;\n                pointer-events: all;\n            }\n\n            :host([opened]) #modal {\n                top: 15vh;\n            }\n\n            #modal {\n                position: fixed;\n                top: 10vh;\n                left: 25%;\n                width: 50%;\n                z-index: 100;\n                background: white;\n                border-radius: 3px;\n                box-shadow: 0 2px 8px rgba(0,0,0,0.26);\n                display: flex;\n                flex-direction: column;\n                justify-content: space-between;\n                opacity: 0;\n                pointer-events: none;\n                transition: all 0.3s ease-out;\n            }\n\n            header {\n                padding: 1rem;\n                border-bottom: 1px solid #ccc;\n            }\n\n            ::slotted(h1) {\n                font-size: 1.25rem;\n                margin: 0;\n            }\n\n            #main {\n                padding: 1rem;\n            }\n\n            #actions {\n                border-top: 1px solid #ccc;\n                padding: 1rem;\n                display: flex;\n                justify-content: flex-end;\n            }\n\n            #actions button {\n                margin: 0 0.25rem;\n            }\n        &#x3C;/style>\n        &#x3C;div id=\"backdrop\">&#x3C;/div>\n        &#x3C;div id=\"modal\">\n            &#x3C;header>\n                &#x3C;slot name=\"title\">Please Confirm Payment&#x3C;/slot>\n            &#x3C;/header>\n            &#x3C;section id=\"main\">\n                &#x3C;slot>&#x3C;/slot>\n            &#x3C;/section>\n            &#x3C;section id=\"actions\">\n                &#x3C;button id=\"cancel-btn\">Cancel&#x3C;/button>\n                &#x3C;button id=\"confirm-btn\">Okay&#x3C;/button>\n            &#x3C;/section>\n        &#x3C;/div>\n    `;\n  }\n\n  //this function will run if there is anything that is changed in the shadow DOM\n  attributeChangedCallback(name, oldValue, newValue) {\n    if (this.hasAttribute(\"opened\")) {\n      this.isOpen = true;\n    } else {\n      this.isOpen = false;\n    }\n  }\n\n  static get observedAttributes() {\n    return [\"opened\"];\n  }\n\n  open() {\n    this.setAttribute(\"opened\", \"\");\n    this.isOpen = true;\n  }\n}\n\n//registering custom element named as uc-modal\ncustomElement.define(\"uc-modal\", Modal);\n</code></pre>\n<p>Update index.html with the following code</p>\n<pre><code class=\"language-html\">&#x3C;!DOCTYPE html>\n&#x3C;html lang=\"en\">\n  &#x3C;head>\n    &#x3C;meta charset=\"UTF-8\" />\n    &#x3C;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    &#x3C;meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n    &#x3C;title>Web Components&#x3C;/title>\n    &#x3C;style>\n      * {\n        box-sizing: border-box;\n      }\n\n      body {\n        margin: 2rem;\n        font-family: sans-serif;\n      }\n    &#x3C;/style>\n    &#x3C;script src=\"modal.js\">&#x3C;/script>\n  &#x3C;/head>\n  &#x3C;body>\n    &#x3C;uc-modal>\n      &#x3C;h1 slot=\"title\">Please Confirm&#x3C;/h1>\n      &#x3C;p>With your confirmation you agree to pay the full amount!&#x3C;/p>\n    &#x3C;/uc-modal>\n    &#x3C;p>Please confirm your choice.&#x3C;/p>\n    &#x3C;button>Show Details &#x26; Confirm&#x3C;/button>\n    &#x3C;script>\n      const confirmButton = document.querySelector(\"button\");\n      const modal = document.querySelector(\"uc-modal\");\n\n      confirmButton.addEventListener(\"click\", () => {\n        //  modal.setAttribute('opened', '');\n        if (!modal.isOpen) {\n          modal.open();\n          console.log(\"Opening...\");\n        }\n      });\n    &#x3C;/script>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre>\n<h4>Step 4: Listening to slot content change and Adding methods to close the modal</h4>\n<ul>\n<li>\n<p>We will be adding code to listen to slot changes as explained earlier slot is the way to get the content from outside the web component</p>\n</li>\n<li>\n<p>We will be adding <strong><em>hide</em></strong> method to hode the modal</p>\n</li>\n<li>\n<p>We will be adding <strong><em>_cancel</em></strong> method and <strong><em>_confirm</em></strong> method to close the modal on Cancel and Confirm click</p>\n</li>\n</ul>\n<p>Update the modal.js file with the following code</p>\n<pre><code class=\"language-js\">class Modal extends HTMLElement {\n  constructor() {\n    super();\n    this.attachShadow({ mode: \"open\" });\n    this.isOpen = false;\n    this.shadowRoot.innerHTML = `\n        &#x3C;style>\n            #backdrop {\n                position: fixed;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100vh;\n                background: rgba(0,0,0,0.75);\n                z-index: 10;\n                opacity: 0;\n                pointer-events: none;\n            }\n\n            :host([opened]) #backdrop,\n            :host([opened]) #modal {\n                opacity: 1;\n                pointer-events: all;\n            }\n\n            :host([opened]) #modal {\n                top: 15vh;\n            }\n\n            #modal {\n                position: fixed;\n                top: 10vh;\n                left: 25%;\n                width: 50%;\n                z-index: 100;\n                background: white;\n                border-radius: 3px;\n                box-shadow: 0 2px 8px rgba(0,0,0,0.26);\n                display: flex;\n                flex-direction: column;\n                justify-content: space-between;\n                opacity: 0;\n                pointer-events: none;\n                transition: all 0.3s ease-out;\n            }\n\n            header {\n                padding: 1rem;\n                border-bottom: 1px solid #ccc;\n            }\n\n            ::slotted(h1) {\n                font-size: 1.25rem;\n                margin: 0;\n            }\n\n            #main {\n                padding: 1rem;\n            }\n\n            #actions {\n                border-top: 1px solid #ccc;\n                padding: 1rem;\n                display: flex;\n                justify-content: flex-end;\n            }\n\n            #actions button {\n                margin: 0 0.25rem;\n            }\n        &#x3C;/style>\n        &#x3C;div id=\"backdrop\">&#x3C;/div>\n        &#x3C;div id=\"modal\">\n            &#x3C;header>\n                &#x3C;slot name=\"title\">Please Confirm Payment&#x3C;/slot>\n            &#x3C;/header>\n            &#x3C;section id=\"main\">\n                &#x3C;slot>&#x3C;/slot>\n            &#x3C;/section>\n            &#x3C;section id=\"actions\">\n                &#x3C;button id=\"cancel-btn\">Cancel&#x3C;/button>\n                &#x3C;button id=\"confirm-btn\">Okay&#x3C;/button>\n            &#x3C;/section>\n        &#x3C;/div>\n    `;\n    const slots = this.shadowRoot.querySelectorAll(\"slot\");\n    slots[1].addEventListener(\"slotchange\", (event) => {\n      console.dir(slots[1].assignedNodes());\n    });\n    const backdrop = this.shadowRoot.querySelector(\"#backdrop\");\n    const cancelButton = this.shadowRoot.querySelector(\"#cancel-btn\");\n    const confirmButton = this.shadowRoot.querySelector(\"#confirm-btn\");\n    backdrop.addEventListener(\"click\", this._cancel.bind(this));\n    cancelButton.addEventListener(\"click\", this._cancel.bind(this));\n    confirmButton.addEventListener(\"click\", this._confirm.bind(this));\n  }\n\n  attributeChangedCallback(name, oldValue, newValue) {\n    if (this.hasAttribute(\"opened\")) {\n      this.isOpen = true;\n    } else {\n      this.isOpen = false;\n    }\n  }\n\n  static get observedAttributes() {\n    return [\"opened\"];\n  }\n\n  open() {\n    this.setAttribute(\"opened\", \"\");\n    this.isOpen = true;\n  }\n\n  hide() {\n    if (this.hasAttribute(\"opened\")) {\n      this.removeAttribute(\"opened\");\n    }\n    this.isOpen = false;\n  }\n\n  _cancel(event) {\n    this.hide();\n  }\n\n  _confirm() {\n    this.hide();\n  }\n}\n\ncustomElements.define(\"uc-modal\", Modal);\n</code></pre>\n<p>Update the index.html file with the following code</p>\n<pre><code class=\"language-html\">&#x3C;!DOCTYPE html>\n&#x3C;html lang=\"en\">\n  &#x3C;head>\n    &#x3C;meta charset=\"UTF-8\" />\n    &#x3C;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    &#x3C;meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n    &#x3C;title>Web Components&#x3C;/title>\n    &#x3C;style>\n      * {\n        box-sizing: border-box;\n      }\n\n      body {\n        margin: 2rem;\n        font-family: sans-serif;\n      }\n    &#x3C;/style>\n    &#x3C;script src=\"modal.js\">&#x3C;/script>\n  &#x3C;/head>\n  &#x3C;body>\n    &#x3C;uc-modal>\n      &#x3C;h1 slot=\"title\">Please Confirm&#x3C;/h1>\n      &#x3C;p>With your confirmation you agree to pay the full amount!&#x3C;/p>\n    &#x3C;/uc-modal>\n    &#x3C;p>Please confirm your choice.&#x3C;/p>\n    &#x3C;button>Show Details &#x26; Confirm&#x3C;/button>\n    &#x3C;script>\n      const confirmButton = document.querySelector(\"button\");\n      const modal = document.querySelector(\"uc-modal\");\n\n      modal.addEventListener(\"confirm\", () => {\n        console.log(\"Confirmed...\");\n      });\n\n      modal.addEventListener(\"cancel\", () => {\n        console.log(\"Cancelled...\");\n      });\n\n      confirmButton.addEventListener(\"click\", () => {\n        //  modal.setAttribute('opened', '');\n        if (!modal.isOpen) {\n          modal.open();\n          console.log(\"Opening...\");\n        }\n      });\n    &#x3C;/script>\n  &#x3C;/body>\n&#x3C;/html>\n</code></pre>","fields":{"slug":"/web-component-javascript/"},"frontmatter":{"title":"Creating web component in javascript","date":"June 11, 2023","description":"In this article i will explain you how you can create custom web component in javascript","bannerimage":"https://crew-code-images.s3.us-east-1.amazonaws.com/blog_images/web-component.jpeg"}},"previous":{"fields":{"slug":"/testing-using-jest-and-puppeteer-javascript/"},"frontmatter":{"title":"Testing using jest and puppeteer in nodejs","date":"June 01, 2023","bannerimage":"https://crew-code-images.s3.us-east-1.amazonaws.com/blog_images/puppetter.jpeg"}},"next":{"fields":{"slug":"/working-with-api-in-nextjs/"},"frontmatter":{"title":"Working on API using MongoDB with NextJS","date":"June 25, 2023","bannerimage":"https://metacognitive.me/wp-content/uploads/2024/06/1_7IFWIqKtcdK7KOoMAopLqQ.png"}}},"pageContext":{"id":"d4aefb01-f69c-5a6f-a0de-824fe424b563","previousPostId":"e0ea46b7-1202-5ffc-88c2-6e2236f40254","nextPostId":"90623196-5c56-5c0d-893a-95ae900c3e8c"}},
    "staticQueryHashes": ["3860684146"]}