Web Components – Why?
At the beginning of my career, we mainly worked with Joomla. Over time, various custom requirements and our own ideas emerged, which led to the development of custom Joomla modules. As the years went by, additional CMS platforms such as Contao and WordPress were added. This confronted us with a major issue: the code of our Joomla modules could only partially be reused for modules in other CMS systems. And that’s not all – with every port, a new project was created that had to be maintained and kept up to date. So what could we do?
This is where Web Components come into play. They are platform-independent and supported by all modern browsers. No more CMS-specific special solutions and only one single project that needs to be maintained. Turning the module into a Web Component is the logical next step.
What are Web Components?
Web Components are a technology that allows developers to create reusable elements whose code runs encapsulated from the main DOM. Three core technologies are used for this:
Custom Elements
Custom Elements allow developers to define their own HTML tags and their functionality.
Shadow DOM
Although Web Components appear in the DOM, they are actually rendered inside the Shadow DOM. This DOM tree is attached to the main DOM and ensures that the component’s code runs independently from the rest of the document.
HTML Templates & Slots
Templates make it possible to create reusable markup structures, while slots define where and how content is inserted into those templates.
Creating the Angular Project
The first step is, of course, to create the Angular project. This can easily be done with the following command:
ng new <project-name> --no-standalone
Although Angular supports Web Components out of the box, the required libraries are not added automatically when creating a new project. They must be installed manually using the following command:
npm i @angular/elements
The project is now ready to be converted into a Web Component.
Converting the Project into a Web Component
app.module.ts
The first step is to adjust the app.module.ts file. The class is extended
with the Angular hook DoBootstrap, and an injector is added via the
constructor, which is then used to define our Custom Element.
Inside the ngDoBootstrap hook, the Web Component is defined and made available. The createCustomElement function creates a Custom Element based on an Angular component (in our case, AppComponent). Using customElements.define, we define the tag name that will be used to insert the Web Component into the DOM. When naming the tag, the following rules must be respected:
- The tag name must start with a lowercase alphabetical character (a–z).
- The tag name must contain at least one hyphen (-).
- Existing HTML tags cannot be used as tag names.
- The tag name must not contain symbols (such as =, @, $, etc.).
This page on webcomponents.guide provides a tool to validate component names and lists the naming rules in more detail.
export class AppModule implements DoBootstrap {
constructor(readonly injector: Injector) {}
ngDoBootstrap(): void {
const webArticle = createCustomElement(AppComponent, {
injector: this.injector,
});
customElements.define('web-article', webArticle);
}
}
Finally, the following line must be removed to prevent the Angular error NG05104:
bootstrap: [AppComponent]
Extending main.ts
After adjusting app.module.ts, the main.ts file must also be modified as follows to prevent the Angular error NG0908:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import 'zone.js';
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
Building the Web Component
To use the component, a build must be created using the following command:
ng build --output-hashing none
Note the use of --output-hashing none.
By default, Angular appends a new hash to the generated main file name with every build. Since the file is imported by name, updates are much easier to manage when the hash is disabled using this flag.
Alternatively, a script can be added to the package.json.
After building, the generated code can be found at the following path:
<project-directory>/dist/<project-name>/browser/main.js
Integrating the Web Component
A Web Component is integrated into a website in three simple steps:
- Upload the generated main.js file.
- Include the main.js file using a script tag.
- Insert the Web Component using the tag defined in app.module.ts.
Each of these steps may differ slightly depending on the system used.
HTML5
Integrating a Web Component into a static HTML5 page is very straightforward. Simply add a script tag in the head of the HTML file that points to the main.js file. The Web Component can then be inserted using the defined tag:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Angular Social Feed</title>
<script src="web-article/dist/web-article/browser/main.js"></script>
</head>
<body>
<web-article></web-article>
</body>
</html>
Contao
To use Web Components with Contao, the main.js file is uploaded via the backend UI into a public directory. It can then be included through a page layout (Themes → Page Layouts) using the menu item External JavaScripts.
The Web Component will then be available on every page that uses this layout and can be inserted anywhere using a module or an HTML block.
When inserting via a content element, the element Unfiltered HTML should be used. Otherwise, Contao may replace the tag brackets with HTML entities, resulting in only the tag name being displayed.
Joomla
After uploading main.js via FTP, it must be added to the template head. Joomla templates usually provide this option directly in the template settings (System → Site Template Styles → Template).
If the template does not offer this option, the main.js can be added via the template’s index.php file, which can be edited under System → Site Templates → Template.
Warning: This method should only be used if no other option is available. Modifying core template files is discouraged, as changes may be lost during updates.
Once the main.js file has been included in the head, the Web Component can be inserted anywhere on the page using its defined tag, for example via a custom module.
WordPress
Integrating a Web Component into WordPress is slightly more complex, as the main.js file must be imported after being uploaded. First, upload the file to the following path:
<WP-ROOT>/wp-content/themes/<THEME>/<CUSTOM-DIRECTORY>/
After uploading the file, an import script must be added. This can be done via the backend under Tools → Theme File Editor. Select the theme into which the JS file was uploaded, then add the following code to the functions.php file:
function add_webcomponent() {
wp_register_script(
'web-component-script',
get_template_directory_uri() . '/web-component/main.js'
);
wp_enqueue_script('web-component-script');
}
add_action('wp_enqueue_scripts', 'add_webcomponent');
This PHP function add_webcomponent registers a new script named web-component-script, which imports the main.js file into the WordPress page and then executes it. The function is executed automatically via the WordPress hook. The names add_webcomponent and web-component-script can be chosen freely.
After adding this function, the Web Component can be inserted into a WordPress page, for example using a Custom HTML block.