DEV Community

Cover image for What are Custom HTML Elements?
Joe Erickson
Joe Erickson

Posted on • Edited on • Originally published at jerickson.net

What are Custom HTML Elements?

As I've been looking at how to structure my JavaScript in my applications using modern JavaScript frameworks, I keep running into the same issue. I want to use component-based design, but I'm not always looking to build a Single Page Application. Sometimes, I just want to add a component onto a page that isn't tied to the framework at all.

In a framework like Angular, that's fairly impossible. I've always seen Angular as an all or nothing framework. It's either all Angular or none of it is. And if I have a legacy application that I want to upgrade little by little, all or nothing isn't what I'm looking for.

Vue labels itself as an "incrementally adoptable" framework for modern JavaScript components. I've found this to be generally true but I've been struggling a bit on how best to incrementally adopt it. Do I just start creating Vue instances and put all my JavaScript in there? Do I build components and then try to figure out how to get that started with my current big application? How do I not load all the components for every page when my pages only use a small subset of components? Does that mean I have to give up my idea of a global JavaScript file and now create a JavaScript file for each page? And isn't that what I'm trying to avoid?!?

When playing around with the Vue CLI, I noticed that there was an option to build the Vue components as native web components. Trying to figure out what that means, I dove into the documentation.

Web Components Standard

The Web Components Standard is a standard that's been adopted by the major browsers as a way for developers to create their own HTML elements.

This may sound strange at first and not very useful. Why would we want to create a new <div> or <p> tag? But there are some HTML elements that have a lot of useful functionality behind them, like <video>, <canvas>, and even the <select> element.

<select> is actually built with a number of cool features. By default, you can define a select box and a number of <option>s and the browser knows to show that to the user as a dropdown selection and to limit the user to only selecting one. If you pass the attribute multiple, the functionality changes to allow the user to pick more than one option and displays the control as a scrollbox rather than a dropdown.

This shows just how complex simple components can be. They have structure (a select contains options), presentation (shows as a dropdown or scrollbox), and logic (user input is validated on whether they can select multiple options or not). This functionality sounds a lot like JavaScript components!

Constructing a simple custom element

If you know how to build a component in Vue, you already know how to build a custom HTML element, just make a new standalone Vue component!

Since Vue components are used as if they were HTML elements, if you build a standard single file component in Vue, you can export that as a new HTML element from your project.

I hope to walk through this process in another post, but we can take a look at a quick example now.

I remember the wonder years of 1999 web development. Anything was possible then, including the wonderful <blink> tag. Sadly, every browser killed this poor tag some time ago, but we can bring it back in fashion!

Below, I define a new component that will take whatever is between its tags and blink it. Just like the good ol' days!

<template>
  <span ref="blinkyText"><slot></slot></span>
</template>

<script>
export default {
  name: "blink",
  mounted() {
    setInterval(() => {
      this.$refs.blinkyText.classList.toggle("onoff");
    }, 500);
  }
};
</script>

<style>
.onoff {
  visibility: hidden;
}
</style>
Enter fullscreen mode Exit fullscreen mode

I can then compile this into a custom HTML element using the VueCLI and deploy it to any old webpage with something like this:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.8/dist/vue.js"></script>
<script src="/js/my-blink.min.js" defer></script>

<my-blink>Party Like It's 1999!!!</my-blink>
Enter fullscreen mode Exit fullscreen mode

This tag is decoupled from any framework or other JavaScript. You don't need a main.js or anything else to mount this tag or get it started. You just include the Vue JavaScript file, your tag JavaScript file, and then use the tag like any other HTML tag!

Future articles will cover more

I'll eventually write up a couple of articles around how to build this style of Vue component and how to tie it into Vuex to allow these components to talk to each other. Here are some that are already done:

Top comments (0)