What is Web Component

WebCompoent is officially a different set of technologies that allow you to create reusable custom elements whose functionality is encapsulated outside of your code and use them in your Web applications.

That is, it is a set of technologies that enable componentization of native implementations. This means that Web Components are browser-natively supported components that can be used in any framework or native environment!

As you can see from MDN’s description, Web Components are designed to address code reuse, component customization, reuse management, and more. They can be used together to create custom elements that encapsulate functionality and can be reused anywhere you like without worrying about code conflicts.

How to write a Web Component

Prior to Vue3.2, writing native Web Component components required additional learning of Web Component syntax, lifecycle, and concepts such as Custom elements, Shadow DOM, and HTML Templates.

Vue3.2’s defineCustomElement API solves this problem by simply encapsulating your Vue components as Web components.

defineCustomElement API

Now that Vue 3.2 has been released, it’s easier than ever to create native custom elements from Vue components with defineCustomElement.

In this article, you’ll learn how to use this new API to convert a Vue component into a Web component, how to package it as a library, and how to use it in pure HTML.

The create element – the custom – scaffolding

The create-custom-element scaffold makes it easy to create a vue project that supports the defineCustomElementAPI

NPM: NPM init custom-element yarn: yarn create custom-element PNPM: PNPM create custom-elementCopy the code

A CUSTOM – Element project that supports TS is created using scaffolding

After opening the project and installing the dependencies using PNPM I, we learn how to use defineCustomElement by studying the scaffold template

The directory structure

The directory structure here is similar to that of the Viet-Vue project

Create custom elements

First look at the SRC/CustomElement/index. Ce. Vue

The first step is to create a Vue component that we want to use as a custom element. In this example, we will build a button that can toggle dark themes on the site.

<script setup lang='ts'> import { ref } from 'vue' const isDark = ref(false) </script> <template> <button @click="isDark =! IsDark "> < span v - if =" isDark "> 🌙 < / span > < span v - else > 🌞 < / span > < / button > < / template >Copy the code

Nothing special here, just create a VUE component using VUE syntax

From Vue components to Web Components

To see the SRC/CustomElement/index. Ts

import { defineCustomElement } from 'vue'
import VueDarkModeSwitch from './index.ce.vue'

// Vue generates a new HTML element class from the component definition.
export const DarkModeSwitch = defineCustomElement(VueDarkModeSwitch)

// Register the custom element so that it can be used as <dark-mode-switch>.
export function register (tagName: string = 'dark-mode-switch') {
  customElements.define(tagName, DarkModeSwitch)
}
Copy the code

This file is key to making Vue components packaged as WebComponet:

  1. Start by importing a defineCustomElement from vue

    import { defineCustomElement } from 'vue'

  2. Reintroduce the vue component you wrote earlier and name it VueDartModeSwitch (the name here can be customized to your needs)

    import VueDarkModeSwitch from './index.ce.vue'

  3. Wrap the VueDartModeSwitch with defineCustomElement and export it

    export const DarkModeSwitch = defineCustomElement(VueDarkModeSwitch)

  4. Export the Register method to customize component label names

    export function register (tagName: string = 'dark-mode-switch') { 
        customElements.define(tagName, DarkModeSwitch) 
    }
    Copy the code

Add styles to components

Back in the SRC/CustomElement/index. Ce. Vue file

Some of you may wonder why the vue file ends in.ce.vue.

Ce is short for CustomElemtn, and vue by default files ending in.ce.vue will be imported as a Web Component.

The purpose of this is to enable vue components to support Shadow DOM in files ending in.ce.vue. Style tags can be isolated without the scoped attribute.

Knowing why, now style our component:

<style>
:host{-color: #fbbf24;
  --bg-normal: #fAfAf9;
  --bg-active: #f5f5f4;
  --font-size: 24px;
}

:host([dark]{-color: #fef3c7;
  --bg-normal: # 262626;
  --bg-active: #2d2d2d;
}

button {
  background-color: var(--bg-normal);
  border: none;
  border-radius:.5rem;
  color: var(--color);
  cursor: pointer;
  display: flex;
  font-size: var(--font-size);
  overflow: hidden;
  padding: 0.4 em;
  transition: background-color 0.3 s ease, color 0.3 s cubic-bezier(0.64.0.0.78.0);
}

button:hover.button:focus {
  background-color: var(--bg-active);
  outline: none;
}

.slide-enter-active..slide-leave-active {
  transition: transform 0.3 s ease-out;
}

.slide-enter-from {
  transform: translateY(-150%);
}

.slide-enter-to..slide-leave-from {
  transform: translateY(0);
}

.slide-leave-to {
  transform: translateY(150%);
}
</style>
Copy the code

Use the Web Component

Now go back to the SRC/app.vue file

<script setup lang="ts">
import { register } from './CustomElement';
register('dart-element')
</script>

<template>
  <dart-element></dart-element>
</template>

<style>
#app {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>
Copy the code
  1. First done from encapsulationsrc/CustomElement/index.tsPreviously exported inregistermethods
  2. performregister()Method,registerMethod takes a string argument, a custom tag name
  3. Used in template syntax<dart-element></dart-element>The label

Used in VUE

If we want to use these Web Component components in Vue, we need to configure plugins in vite.config.ts so that Vue can recognize Web Component components and execute them directly, skipping the compilation part of Vue.

plugins: [vue({
    template: {
      compilerOptions: {
        isCustomElement: (tag: string[]) = > tag.includes(The '-')}}})]Copy the code

Of course, these configurations are automatically generated by create-custom-Element scaffolding, so you don’t have to worry about them.

Run a Web Component

It’s time to put this component to the test

pnpm dev

The appearance of this little sun proves that you have succeeded in running!!

We can see from the Element node of DevTools that this is indeed a WebComponent. We get the WebComponent by wrapping a Vue component through the defineCustomElement API

You can run from this page to debug your components

Packaging Web Component

The main purpose of writing a Web Component using VUE is to package it into a common package that can be used in different frameworks

Viet.js provides a packaging mode, so we use viet.js directly for packaging.

build: {
    target: 'esnext'.minify: 'terser'.lib: {
      entry: 'src/CustomElement/index.ts'.formats: ['es'.'cjs'.'iife'].name: 'CustomElement'}}Copy the code

Here will be SRC/CustomElement/index. Ts as entry documents, packaged separately generated three modular specification package.

Use PNPM build for packaging

You can find the three modules packaged in the dist folder

Use Web Components in a native environment

Create an index.html file to import the packaged module

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <script type="module">
    import { register } from './dist/custom-element.es.js'
    register('custom-element')
  </script>
</head>
<body>
  <custom-element></custom-element>
</body>
</html>
Copy the code

Running flawlessly, you can see that the components we wrote in VUE also run successfully in native HTML

End 👋 🏼

Vue defineCustomElement makes developing Web Components easier than ever.

All see here, click a like 👍