Skip to main content

How to dynamic import web components to improve our application performance

If we’re building single-page web application with vanilla web components, we can dynamic import web components to improve the performance.

Let’s say we have a subscribe button on the page and a newsletter subscription modal will pops up should users click this button. This is a basic newsletter-modal web components codes.

./components/newsletterModal.js
export default class newsletterModal extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <!-- component html here -->
      <style>
      /* component styles here */
      </style>
    `;
  }

  show() {
    this.classList.add('visible');
  }

  hide() {
    this.classList.remove('visible');
  }
}

customElements.define('newsletter-modal', newsletterModal);

Here’s codes to achieve dynamic import our newsletter-modal component. 50ms timeout here is when show() is called, we want the newsletter-modal to have a slide animation into the viewport. Not sure if this is a bug or I did something wrong there, but if I leave out the setTimeout there, there is no CSS animations on that newsletter modal. Possible reason is that — just me guessing — our component is not fully ready to animate yet when show() is called, this is such an interesting problem that I should revisit in future.

index.html
<newsletter-modal></newsletter-modal>
index.js
const button = document.querySelector('#subscribe-button');
button.addEventListener('click', (e) => {
  import('./components/newsletterModal.js')
    .then(() => {
      return customElements.whenDefined('newsletter-modal');
    })
    .then(() => {
      const timeout = setTimeout(() => {
        document.querySelector('newsletter-modal').show();
        clearTimeout(timeout);
      }, 50);
    })
    .catch((error) => {
      // your error handling here
      console.error(error);
    });
});

And here’s async/await version.

index.js
const button = document.querySelector('#subscribe-button');
button.addEventListener('click', async (e) => {
  try {
    await import('./components/newsletterModal.js');
    await customElements.whenDefined('newsletter-modal');
    const timeout = setTimeout(() => {
      document.querySelector('newsletter-modal').show();
      clearTimeout(timeout);
    }, 50);
  } catch(error) {
    // your error handling here
    console.error(error);
  }