Client-Side alternative to Server-Side Includes

As an alternative to Server Side Includes, as in PHP include, we can use a client side solution using JavaScript.

I start with the index page that I have created. To follow along, copy and paste the code in a new document.

This is the HTML code for the index page:

<!doctype html>
<html lang="en" class="h-100">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Example using Custom HTML Elements">
    <title>Custom HTML Elements</title>
    <link rel="stylesheet" href="bootstrap/5/css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/style.css" />
    <script src="dmxAppConnect/dmxAppConnect.js"></script>
    <script src="dmxAppConnect/dmxBootstrap5Navigation/dmxBootstrap5Navigation.js" defer></script>
</head>
<body is="dmx-app" id="index" class="h-100 d-flex flex-column">
    <header class="bg-info-subtle">
        <nav class="navbar navbar-expand-lg ">
            <div class="container">
                <a class="navbar-brand ms-auto" href="index.html">Navbar</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar1_collapse" aria-controls="navbar1_collapse" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbar1_collapse">
                    <div class="navbar-nav">
                        <a class="nav-item nav-link active" href="index.html">Home</a>
                        <a class="nav-item nav-link" href="about.html">About</a>
                        <a class="nav-item nav-link" href="contact.html">Contact</a>
                    </div>
                </div>
            </div>
        </nav>
    </header>
    <main class="flex-grow-1 pt-4">
        <div class="container">
            <div class="row">
                <div class="col">
                    <h1>Hello Wapplers!</h1>
                </div>
            </div>
        </div>
    </main>
    <footer class="bg-info-subtle">
        <div class="container">
            <div class="row row-cols-2 row-cols-md-3 text-center pt-4">
                <div class="col">
                    <h5>Features</h5>
                    <ul class="list-unstyled">
                        <li><a class="text-muted" href="#">Cool stuff</a></li>
                        <li><a class="text-muted" href="#">Random feature</a></li>
                        <li><a class="text-muted" href="#">Team feature</a></li>
                        <li><a class="text-muted" href="#">Stuff for developers</a></li>
                        <li><a class="text-muted" href="#">Another one</a></li>
                        <li><a class="text-muted" href="#">Last time</a></li>
                    </ul>
                </div>
                <div class="col">
                    <h5>Resources</h5>
                    <ul class="list-unstyled">
                        <li><a class="text-muted" href="#">Resource</a></li>
                        <li><a class="text-muted" href="#">Resource name</a></li>
                        <li><a class="text-muted" href="#">Another resource</a></li>
                        <li><a class="text-muted" href="#">Final resource</a></li>
                    </ul>
                </div>
                <div class="col">
                    <h5>About</h5>
                    <ul class="list-unstyled">
                        <li><a class="text-muted" href="#">Team</a></li>
                        <li><a class="text-muted" href="#">Locations</a></li>
                        <li><a class="text-muted" href="#">Privacy</a></li>
                        <li><a class="text-muted" href="#">Terms</a></li>
                    </ul>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col">
                    <p class="text-secondary text-center small mb-0 p-1">© Copyright 2024. All Rights Reserved.</p>
                </div>
            </div>
        </div>
    </footer>
    <script src="bootstrap/5/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Similar to Server Side Includes, I want the same header and footer for my other pages. To do this, I create custom elements in a JavaScript file. Here I have prepared a JavaScript file called web-components.js. Again, copy and paste the code in a JavaScript document.

// header element
class Header extends HTMLElement {
  constructor() {
    super()
    this.innerHTML = `
    `
  }
}
window.customElements.define('my-header', Header)
// footer element
class Footer extends HTMLElement {
  constructor() {
    super()
    this.innerHTML = `
    `
  }
}
window.customElements.define('my-footer', Footer)

I will now cut the HTML code from the index page and paste it in the JavaScript file as follows:

// header element
class Header extends HTMLElement {
  constructor() {
    super()
    this.innerHTML = `
        <header class="bg-info-subtle">
        <nav class="navbar navbar-expand-lg ">
            <div class="container">
                <a class="navbar-brand ms-auto" href="index.html">Navbar</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar1_collapse" aria-controls="navbar1_collapse" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbar1_collapse">
                    <div class="navbar-nav">
                        <a class="nav-item nav-link active" href="index.html">Home</a>
                        <a class="nav-item nav-link" href="about.html">About</a>
                        <a class="nav-item nav-link" href="contact.html">Contact</a>
                    </div>
                </div>
            </div>
        </nav>
    </header>
    `
  }
}
window.customElements.define('my-header', Header)
// footer element
class Footer extends HTMLElement {
  constructor() {
    super()
    this.innerHTML = `
        <footer class="bg-info-subtle">
        <div class="container">
            <div class="row row-cols-2 row-cols-md-3 text-center pt-4">
                <div class="col">
                    <h5>Features</h5>
                    <ul class="list-unstyled">
                        <li><a class="text-muted" href="#">Cool stuff</a></li>
                        <li><a class="text-muted" href="#">Random feature</a></li>
                        <li><a class="text-muted" href="#">Team feature</a></li>
                        <li><a class="text-muted" href="#">Stuff for developers</a></li>
                        <li><a class="text-muted" href="#">Another one</a></li>
                        <li><a class="text-muted" href="#">Last time</a></li>
                    </ul>
                </div>
                <div class="col">
                    <h5>Resources</h5>
                    <ul class="list-unstyled">
                        <li><a class="text-muted" href="#">Resource</a></li>
                        <li><a class="text-muted" href="#">Resource name</a></li>
                        <li><a class="text-muted" href="#">Another resource</a></li>
                        <li><a class="text-muted" href="#">Final resource</a></li>
                    </ul>
                </div>
                <div class="col">
                    <h5>About</h5>
                    <ul class="list-unstyled">
                        <li><a class="text-muted" href="#">Team</a></li>
                        <li><a class="text-muted" href="#">Locations</a></li>
                        <li><a class="text-muted" href="#">Privacy</a></li>
                        <li><a class="text-muted" href="#">Terms</a></li>
                    </ul>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col">
                    <p class="text-secondary text-center small mb-0 p-1">© Copyright 2024. All Rights Reserved.</p>
                </div>
            </div>
        </div>
    </footer>
    `
  }
}
window.customElements.define('my-footer', Footer)

All that remains now is to add the custom elements to my pages - including a link to the JavaScript file.

<!doctype html>
<html lang="en" class="h-100">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Example using Custom HTML Elements">
    <title>Custom HTML Elements</title>
    <link rel="stylesheet" href="bootstrap/5/css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/style.css" />
    <script src="dmxAppConnect/dmxAppConnect.js"></script>
    <script src="dmxAppConnect/dmxBootstrap5Navigation/dmxBootstrap5Navigation.js" defer></script>
</head>
<body is="dmx-app" id="index" class="h-100 d-flex flex-column">
    <my-header></my-header>
    <main class="flex-grow-1 pt-4">
        <div class="container">
            <div class="row">
                <div class="col">
                    <h1>Hello Wapplers!</h1>
                </div>
            </div>
        </div>
    </main>
    <my-footer></my-footer>
    <script src="bootstrap/5/js/bootstrap.bundle.min.js"></script>
    <script src="js/web-components.js"></script>
</body>
</html>

I do this for each of the other pages with the following result

The included components will always appear in the design panel.

For more info on custom elements see

10 Likes

Thanks Ben for the detailed tutorial. Custom elements are indeed a great way to group layout and functionality.

We are considering making more natural editor for creating custom elements and app connect components, the same way as you create content pages.

5 Likes

Thanks @ben!!!

At least I got an indirect answer to my topic here:

So, I can create any appconnect element I need and by passing the required attributes in each case, I can make it as custom and dynamic I need...
Not available in the UI but gives a great solution I think!

:+1: :beer:

2 Likes

@george, thank you for your feedback. Condsidering that App Connect extensions are merely a Wapplerised version of web components (widgets), it would be most beneficial to all concerned to have this functionality added to Wappler.

The biggest advantage is the re-usable nature of the widget, not only intra-project, but also for inter-project. A library of widgets can be housed locally, in the community, as a Git repository or NPM.

Imagine a timer function by merely adding <my-timer></my-timer> to a document.

Or a pop-up
<popup-info img="img/alt.png" 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>.

Or a customised built-in element as in <p is="word-count"></p>

Heck, this presents a veritable cornucopia of possibilities.

Looking forward to seeing an editor.

2 Likes