UH Tech
HomeServicesWorkTutorialsAboutContact
Sign InSign Up
UH Tech

UH Tech builds modern digital solutions including MERN stack applications, Shopware plugins, and Wix websites helping businesses grow faster in the digital world.

✉ info@uhtech.solutions
f◎in

Company

HomeAbout UH TechOur WorkTutorialsContact

Services

Wix Velo DevelopmentNext.js & MERN StackShopware 6 PluginsAutomationAll Services

Recent Work

ToolHubMiami Living MagazinePrimax

Get In Touch

Start a ProjectEmail Support
© 2026 UH Tech. All rights reserved.Privacy Policy  ·  Terms of Service

Custom Element in Wix Velo

Home / Tutorials / Custom Element in Wix Velo
Wix VeloMay 30, 2026·12:17·UH Tech

What you'll learn

Learn how to build custom web components in Wix Velo using Shadow DOM. In this tutorial, I'll show you the same patterns we use at UH Tech to build advanced components for real client projects like ElitePetz and Verify Vault. What you'll learn: ✓ Why custom components beat native Wix elements ✓ How to set up a custom element in Wix Editor ✓ What Shadow DOM is and why it matters ✓ How to write your first custom component ✓ Style isolation that just works Perfect for Wix Velo developers who want to go beyond basic components. 🔗 To Get Code: https://github.com/UH-TECH/Custom-Web-Components-in-Wix-Velo 🔗 Need a Wix Velo developer? https://uhtech.solutions 🔗 Connect with us: https://www.linkedin.com/company/uh-technology-software About UH Tech: We're a software studio that builds advanced systems on Wix Velo, Shopware 6, and Next.js. New Wix Velo tutorials every Tuesday. #WixVelo #CustomElements #ShadowDOM #WebComponents #WixTutorial

Code from the video

Web Element in Wix Velo

Wix Velo
// public/admin-table.js


if (!customElements.get('admin-table')) {

  class AdminTable extends HTMLElement {
    constructor() {
      super();
      // Attach Shadow DOM for full encapsulation
      this.attachShadow({ mode: 'open' });
      this._data = [];
    }

    // Tell the browser which attributes to watch
    static get observedAttributes() {
      return ['result'];
    }

    // Lifecycle: when element is added to DOM
    connectedCallback() {
      this.render();
    }

    // Lifecycle: when watched attribute changes
    attributeChangedCallback(name, oldValue, newValue) {
      if (name === 'result' && newValue) {
        try {
          this._data = JSON.parse(newValue);
          this.render();
        } catch (err) {
          console.error('Invalid JSON in result attribute', err);
        }
      }
    }

    render() {
      this.shadowRoot.innerHTML = `
        <style>
          :host {
            display: block;
            font-family: system-ui, sans-serif;
          }
          table {
            width: 100%;
            border-collapse: collapse;
            background: #0A1628;
            color: #fff;
            border-radius: 8px;
            overflow: hidden;
          }
          th, td {
            padding: 12px 16px;
            text-align: left;
            border-bottom: 1px solid #1a2942;
          }
          th {
            background: #8B5CF6;
            font-weight: 600;
          }
          tr:hover td {
            background: #1a2942;
          }
        </style>
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Email</th>
              <th>Status</th>
            </tr>
          </thead>
          <tbody>
            ${this._data.map(row => `
              <tr>
                <td>${row.name}</td>
                <td>${row.email}</td>
                <td>${row.status}</td>
              </tr>
            `).join('')}
          </tbody>
        </table>
      `;
    }
  }

  customElements.define('admin-table', AdminTable);
}
▶

Subscribe for new tutorials

Practical tutorials on Wix Velo, Next.js, Shopware 6, and automation. Real production patterns from the UH Tech studio.

▶ Subscribe to UH Tech