Angular Elements: Create a Component Library for Angular and the Web

Publish Angular components and Custom Elements from a single project! Using the Angular CLI.

Authors
Gary Großgarten Gary Großgarten
Published at

Reuse your Angular components almost everywhere - with Angular Elements.

In this guide you'll learn how to

  • Scaffold a reusable component library.
  • Export the library for Angular and as Web Components.
  • Publish everything to npm.

Let's get started. ⬇

Create the project

This guide uses the Angular CLI 9.0.7 to scaffold most of the project structure and configuration for your reusable UI Library.

First, initialize a new Angular application with ng new APP_NAME. Feel free to use routing and your favorite stylesheet format when prompted.

Open the newly created project in your favorite IDE.

Next, run:

ng g library components

This step will generate a new library under ./projects/components and add an example component. The library is ready to be shared and used in all of your Angular applications without further configuration. 💆

Perform an initial build of the component library by running:

ng build components

Currently, Angular Elements only supports projects of type application to create Custom Elements. This means you need to generate an additional application. The sole purpose of the application is to import your angular components and output them as Custom Elements.

To generate the elements application run:

ng g application elements

Additionally, run the @angular/elements schematic:

ng add @angular/elements --project elements

This will create a new app in the subfolder ./projects/elements and install all the necessary dependencies and polyfills needed to set up Angular Elements.

If you want to publish your components as Custom Elements cd into ./projects/elements and create a package.json using

npm init

Then, add the following to the newly created package.json:

{
  ...
  "files": ["elements.js", "styles.css"],
  ...
}

Your project should now look something like this:

folder structure and package.json content

Configure Angular Elements

In the elements application delete all files in ./projects/elements/src/app except app.module.ts.

You need to define your own bootstrapping method for the elements application. Do some changes to your elements app.module.ts:

  • Remove the bootstrap array from NgModule declaration.
  • Import ComponentsModule and ComponentsComponent from the components library.
  • Add ngDoBootstrap hook.
  • For every component create an element using the createCustomElement function from @angular/elements. Then define the element using web's native customElemments.define function, specifying a selector.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { ComponentsModule, ComponentsComponent } from 'components';

@NgModule({
  imports: [
    BrowserModule,
    ComponentsModule
  ],
  providers: []
})
export class AppModule {

  constructor(private injector: Injector){}

  ngDoBootstrap(){
    const element = createCustomElement(ComponentsComponent, { injector: this.injector })
    customElements.define("lib-components", element);
  }

 }

Remove zone.js (optional)

Removing zone.js is probably a good idea. Read more about it in this great article. Just keep in mind that you need to handle change detection yourself.

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule, { ngZone: 'noop' })
  .catch(err => console.error(err));

Time to build ⚙

In your root package.json add the following scripts:

{
  "scripts": {
    ...
    "build:elements": "ng build --prod --project elements --output-hashing none && npm run pack:elements && cp projects/elements/package.json dist/elements",
    "pack:elements": "cat ./dist/elements/{runtime,polyfills,main}-es5.js > dist/elements/elements.js && ls -lah dist/elements/elements.js",
    "build:components": "ng build --prod --project components",
    ...
  },
  ...
  
}

To build the elements application run:

npm run build:elements

The script exports your Angular components as Custom Elements during the build process. Also it will run the pack:elements script and copy the previously created package.json to ./dist/elements.

The pack:elements script is optional yet very useful because it will bundle the js build outputs into a single elements.js file. This makes it easier to include your library in other applications.

Try it out

Use your Angular components by including them in the root Angular application:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ComponentsModule } from 'components';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ComponentsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
<h1>angular component</h1>
<lib-components></lib-components>

Run the root application with ng s.

angular app running and displaying the component

Using your Custom Elements is simple. Create an index.html in the root of your project and add following code snippet:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="dist/elements/styles.css">
    <script src="dist/elements/elements.js"></script>
</head>
<body>

    <h1>Web Component (Costum Elements)</h1>
    <lib-components></lib-components>
</body>
</html>

To test, serve it on a http server and open the index.html. I'm using serve.

serve .

web component

Publish to npm

The only thing left to do is to publish your components and Custom Elements to npm. This is fairly easy. Either run npm publish dist/components or npm publish dist/elements.

Reminder

Before releasing, you probably want to update ./projects/components/package.json and ./projects/elements/package.json to include your libraries' name and version. A way to name your libraries could be ngx-<NAME> for angular and wc-<NAME> for the Custom Elements.

✨ Congratulations! You successfully created and published a custom Angular component library that can be used almost everywhere!

If you have further questions on the topic, feedback on the article or just want to say hi you can hit me up on twitter.

Table of Contents

Top of Page Sorry, could not load static page content Comments Related Articles

Related Posts

Find more posts like this one.

Authors
Gary Großgarten
September 23, 2021

Media Queries with RxJS

Media Queries | Practical examples with RxJS
RxJS Angular Read More
Authors
Marc Stammerjohann
December 15, 2020

Tailwind CSS Purge: Optimize Angular for Production

Remove unused Tailwind CSS utilities from your Angular production build for best performance
Tailwind CSS Angular Scully Read More
Authors
Marc Stammerjohann
November 09, 2020

Firebase Hosting: Preview and Deploy via GitHub Actions

Preview and Deploy your Angular or Scully app on Firebase Hosting automated via GitHub Actions
Firebase Angular GitHub Read More
Authors
Marc Stammerjohann
October 29, 2020

Jamstack: Angular + Scully + Tailwind CSS

Use Angular's static site generator Scully and style it with Tailwind CSS
Scully Angular Tailwind CSS Read More
Authors
Marc Stammerjohann
June 03, 2021

Angular with Tailwind CSS

Learn how to style Angular applications with Tailwind CSS
Angular Tailwind CSS CSS Read More

more coming soon

Get in Touch!

Sign up for our newsletter

Sign up for our newsletter to stay up to date. Sent every other week.

We care about the protection of your data. Read our Privacy Policy.