Turn an angular6 project into an element in 5 minutes

Angular elements
Angular 6 comes with a new feature. Angular Elements. With this you can now create custom HTML element that you can easily reuse and integrate your project into other projects.
Your existing application
So let’s say you have spend months of coding and created this amazing application. What the application does is retrieve the current Bitcoin information from Bitstamp and displays it in a list using material design:


Above project has just one component and one service but this should not matter. Whatever the size of your application the process should be the same.
First add angular/elements to your project
ng add @angular/elements
npm install @webcomponents/custom-elements --saveChanging your app.module.ts
To use our Angular application as an custom HTML element we need to change 3 things in our app.module.ts file:
- Import createCustomElement
- Define our custom element
- Change bootstrapping to Entrycomponent
First import customElementCreator
import { createCustomElement } from '@angular/elements';Second, define the custom element
We create our custom element by expanding upon our Appmodule() class. Note that ‘btc-price-element’ is how we are going to call our custom HTML element <btc-price-element></btc-price-element>.
Finally, we need to add ngDoBootstrap to override the bootstrapping.
constructor(private injector: Injector) {
const elm = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('btc-price-element', elm);
}
ngDoBootstrap() {
}
}Change bootstrap to entryComponent
//From
bootstrap: [AppComponent]//To
entryComponents: [AppComponent]
Note once you have done this ng serve will show you a blank page. This is normal. Since we now initiate the bootstrapping during the creation of the custom HTML element.
Your app.module.ts should look like something like this:
import {BrowserModule} from '@angular/platform-browser';
import {AppComponent} from './app.component';
import {PriceComponent} from './price/price.component';
import {HttpClientModule} from '@angular/common/http';
import {createCustomElement} from '@angular/elements';
@NgModule({
declarations: [
AppComponent,
PriceComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
entryComponents: [AppComponent]
})
export class AppModule {
constructor(private injector: Injector) {
const elm = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('btc-price-element', elm);
}
ngDoBootstrap() {
}
}ViewEncapsulation
Angular gives multiple options for viewEncapsulation (see the docs). It basically enables us to have a shadow dom and apply styles to our elements without them bleeding out to the host project or vice-versa. We are going to use the standard option:emulated
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
encapsulation: ViewEncapsulation.Emulated
})Now if we build the project we get a lot of files. It’s not handy to have to import so many files into our host project so let’s dome something about that.

Create an file elements-build.js in the root of your project folder and add the following (change your project name accordingly):
const fs = require('fs-extra');
const concat = require('concat');
(async function build() {
let projectName = 'btcElement';
const files = [
'./dist/'+ projectName +'/runtime.js',
'./dist/'+ projectName +'/polyfills.js',
'./dist/'+ projectName + '/scripts.js',
'./dist/'+ projectName +'/main.js'
];
await fs.ensureDir('elements');
await concat(files, 'elements/'+ projectName +'.js');
await fs.copyFile(
'./dist/'+ projectName +'/styles.css',
'elements/styles.css'
);
})();Building and using the element
We build our project and run the node script below (you can also turn this into a task):
ng build --prod && node elements-build.jsNow we are left with just one javascript file and one stylesheet.
So for example you have a website build on any kind of framework or language with an HTML file like below:

And let’s say we wan’t to replace our third column with our custom Angular element. We could easily do this like so:

Which will result in you application being run inside that div as you can see below.

important! make sure that you have your target set to: “es6” in your tsconfig.json file. This won’t work on es5.
That’s it
It took me a bit of time figuring it out so i hope this can maybe help others create their first Angular element a little bit faster. Here is the btc project if you want to take a look for yourself.