Managing Web Components at Scale with Zesty

In Part 1, we built a lean, mean conversion page using Web Components—no heavy frameworks, no endless dependencies. Now imagine managing dozens of these components across multiple sites from one central, powerful hub. That’s where Zesty CMS steps in.

Why Scale with Zesty?

Centralized Management and Variants

When you're juggling multiple Web Components across various projects, updates can quickly become a headache. Zesty offers a centralized dashboard that makes it simple to:

  • Manage All Your Components: Update and maintain every Web Component from one intuitive interface.
  • Version Control: Experiment with new designs and roll back changes when needed—without the usual stress.
  • Manage Variants: Easily create and toggle between multiple variants of a component so you always deliver the most effective, context-sensitive content.
  • Live Content Updates: Push updates to your components in real time, completely eliminating manual code changes.

Dynamic Rendering

Zesty’s headless architecture empowers you to render Web Components dynamically:

  • Personalized Experiences: Serve different versions of a component based on user behavior or locale.
  • API-Driven Updates: Refresh your content on the fly and deliver it seamlessly through APIs.
  • Parsley: Leverage Zesty’s templating language, Parsley, for a hybrid rendering approach. This lets you dynamically render components while still benefiting from the performance perks of static hosting—giving you unparalleled flexibility and speed.

Scalable Hosting

Not only does Zesty help you manage your components, but it also hosts them centrally. This means you can be confident that your components are:

  • Consistently Available: Delivered via Zesty’s global CDN, ensuring fast load times no matter where your audience is.
  • Secure and Reliable: Built-in security and scalability mean you never have to worry about traffic spikes or downtime.

Building a Conversion Form Using Zesty

Now that we've covered why Zesty is a game changer, let’s get hands-on. We’re going to recreate the conversion form from Part 1—but this time, we’ll harness Zesty’s robust management and hosting features.

Step 1: Create an Account

  1. Head over to Zesty.io and create an account.

Step 2: Create a New Instance

  1. Create a new blank instance and select hybrid as your tech stack. This lets you use both headless functionality and Parsley for rendering.

Step 3: Open the Instance Manager

  1. Click on Open Manager on your instance to navigate into the instance manager UI.

Step 4: Create a New Model

  1. In the navigation side panel, click on Schema.
  2. Click on Create New Model, select the Block type, and name it conversion-form. Blocks are used to store your HTML templates.

Step 5: Add Dynamic Fields

  1. In the model view, add fields to your model so you can reference them dynamically. For example, add a single-line text field called title to later drive dynamic templating

Step 6: Edit the Template File

  1. Click on Edit Template File (or Edit in Code) to open the model’s code file. Remove the placeholder template and insert your HTML template from Part 1:
<div id="conversion-form-template">
  <style>
    .form-container {
      font-family: Arial, sans-serif;
      background: #fff;
      border: 1px solid #ddd;
      padding: 20px;
      border-radius: 8px;
      text-align: center;
      box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
      max-width: 350px;
      margin: auto;
    }
    h2 {
      color: #333;
    }
    p {
      color: #666;
      font-size: 14px;
    }
    input {
      width: 100%;
      padding: 10px;
      margin: 8px 0;
      border: 1px solid #ccc;
      border-radius: 4px;
      font-size: 16px;
    }
    button {
      background: #007bff;
      color: white;
      padding: 10px 15px;
      border: none;
      border-radius: 4px;
      font-size: 16px;
      cursor: pointer;
      width: 100%;
      transition: background 0.3s;
    }
    button:hover {
      background: #0056b3;
    }
    .success-message {
      display: none;
      color: green;
      margin-top: 10px;
      font-weight: bold;
    }
  </style>
  <div class="form-container">
    <!-- Make title dynamic using Parsley -->
    <h2>{{this.title}}</h2>
    <p>Sign up now and receive an exclusive discount.</p>
    <input type="text" id="name" placeholder="Your Name" required />
    <input type="email" id="email" placeholder="Your Email" required />
    <button id="submit-btn">Get My Discount</button>
    <p class="success-message">Thanks! Your discount code is on its way. 🎉</p>
  </div>
</div>

Step 7: Save and Publish

  1. Save and publish your changes. Your template is now hosted automatically at a URL like:
    https://<your_instance_domain>/-/block/conversion_form.html

    (Here is mine: https://webcomponentsdemo-vp0gk4kr.zesty.dev/-/block/conversion_form.html)

Step 8: Update Your Homepage

  1. Open your homepage’s code file in the Code App. Replace the relative path for the template in your Web Component with the hosted URL. For example, change:
const response = await fetch("conversion_form.html");

to

const response = await fetch("https://webcomponentsdemo-vp0gk4kr.zesty.dev/-/block/conversion_form.html");

Here’s the complete updated html:

    <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Exclusive Offer - Get 20% Off Your First Order</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        background: #f4f4f4;
        font-family: Arial, sans-serif;
        color: #333;
        text-align: center;
      }
      header {
        background: #007bff;
        color: #fff;
        padding: 20px;
      }
      header h1 {
        margin: 0;
        font-size: 2em;
      }
      .hero {
        padding: 40px 20px;
        background: #e9f3ff;
      }
      .hero h1 {
        font-size: 2.5em;
        margin-bottom: 10px;
      }
      .hero p {
        font-size: 1.2em;
        margin-bottom: 20px;
      }
      .container {
        padding: 20px;
        max-width: 800px;
        margin: 0 auto;
      }
      footer {
        background: #007bff;
        color: #fff;
        padding: 10px;
        position: fixed;
        bottom: 0;
        width: 100%;
        font-size: 0.9em;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>Exclusive Offer</h1>
    </header>

    <section class="hero">
      <h1>Unlock Your 20% Discount Today!</h1>
      <p>Join our community and enjoy exclusive savings on your first purchase.</p>
    </section>

    <section class="container">
      <!-- Our conversion form web component -->
      <conversion-form></conversion-form>
    </section>

    <footer>
      <p>&copy; 2025 Your Company. All Rights Reserved.</p>
    </footer>

    <script>
      class ConversionForm extends HTMLElement {
        constructor() {
          super();
          this.attachShadow({ mode: "open" });
        }

        async connectedCallback() {
          try {
            const response = await fetch("https://webcomponentsdemo-vp0gk4kr.zesty.dev/-/block/conversion_form.html");
            if (!response.ok) {
              throw new Error("Network response was not ok");
            }
            const htmlText = await response.text();
            const tempContainer = document.createElement("div");
            tempContainer.innerHTML = htmlText;
            // Grab the template by its id (adjust if necessary)
            const template = tempContainer.querySelector("#conversion-form-template");
            if (template) {
              this.shadowRoot.appendChild(template.cloneNode(true));
              this.setupForm();
            } else {
              console.error("Template not found in conversion_form.html");
            }
          } catch (error) {
            console.error("Error fetching the template:", error);
          }
        }

        setupForm() {
          this.nameInput = this.shadowRoot.querySelector("#name");
          this.emailInput = this.shadowRoot.querySelector("#email");
          this.submitButton = this.shadowRoot.querySelector("#submit-btn");
          this.successMessage = this.shadowRoot.querySelector(".success-message");
          this.submitButton.addEventListener("click", this.handleSubmit.bind(this));
        }

        handleSubmit() {
          const name = this.nameInput.value.trim();
          const email = this.emailInput.value.trim();

          if (!name || !email) {
            alert("Please fill out both fields.");
            return;
          }

          console.log("Customer Data Sent:", { name, email });
          this.successMessage.style.display = "block";
          this.nameInput.value = "";
          this.emailInput.value = "";
        }
      }

      customElements.define("conversion-form", ConversionForm);
    </script>
  </body>
</html>

Save and publish your changes. Since this is your homepage, the updated conversion form should now be live at your root path (e.g., https://webcomponentsdemo-vp0gk4kr.zesty.dev).

Step 9: Enabling Variants and Version Control

To take full advantage of variants and version control, we need to make our template dynamic.

  1. Make the Template Dynamic:
    Return to the Code App and edit the conversion_form.html file. Change the static title <h2>Get 20% Off Your First Order!</h2> to use the dynamic field you added earlier:

    <h2>{{this.title}}</h2>
    

    Save and publish your changes.

  2. Create a Variant:
    Navigate to the Blocks App and select your conversion_form block. Click on Create Variant and name the first variant “Default.”
    In the variant editor, enter an alternative title (for example, “Get 30% Off Your First Order!”) and save the variant. Preview it and publish once you’re satisfied.

  3. Switching Variants on the Homepage:
    To use a specific variant, copy the ZUID (Zesty’s unique identifier) for that variant via the ellipses menu.
    Then, update your homepage code’s fetch URL to include the variant parameter. For example:

const response = await fetch("https://webcomponentsdemo-vp0gk4kr.zesty.dev/-/block/conversion_form.html?variant=7-92ebf9a0b0-t9qwk9");

You can also specify a version if needed, for example:

const response = await fetch("https://webcomponentsdemo-vp0gk4kr.zesty.dev/-/block/conversion_form.html?variant=7-92ebf9a0b0-t9qwk9&version=3");

Publish your homepage and see the changes in action.

Using Variants in Parsley for Server Rendering

If you crave even more control and speed, imagine bypassing client-side fetching entirely. With Parsley, you can server-render your Web Components seamlessly—no JavaScript waiting around in the browser. Instead, your server delivers fully rendered, dynamic HTML directly to your users, which means lightning-fast load times and an instant, polished experience.

By replacing your client-side Web Component code () with:

{{block('/-/block/conversion_form.html')}}

or by specifying a variant and version:

{{block('/-/block/conversion_form.html?variant=7-92ebf9a0b0-t9qwk9&version=3')}}

you empower your site with the ultimate in performance and flexibility. This server-rendered approach harnesses the dynamic power of Parsley while ensuring your pages load with the speed and reliability of static hosting.

Conclusion

Web development is evolving, and so is the need for scalable, maintainable, and high-performance UIs. With Web Components, you can build a lean, framework-independent solution that simplifies your code and streamlines your workflow. Integrating this approach with Zesty CMS brings centralized management, robust hosting, and dynamic rendering with Parsley into one cohesive system.

Imagine being able to control every conversion form, interactive element, and dynamic page from a single dashboard, updating content in real time and delivering pages with consistent speed worldwide. This workflow provides a practical solution for building, managing, and deploying Web Components at scale. Whether you opt for client-side rendering or leverage server-side rendering with Parsley, these tools help keep your digital experiences fresh, dynamic, and efficient.

By following these steps, you now have a complete workflow to build and maintain conversion forms and other Web Components at scale, simplifying your development process and enhancing your digital presence.