Web Components is a suite of different technologies allowing you to create reusable custom user interface components.
In this article, we’ll explore how to create custom Web Components using Stencil.js and integrate them into Angular applications.
What is Stencil.js?
Stencil is an open-source compiler that generates standards-compliant web components. It builds highly performant, reusable components that can be used with any JavaScript framework or library. Created by the Ionic team, Stencil combines the best features of popular frameworks like Angular, React, and Vue, providing a simple and efficient way to build custom elements.
Advantages of Stencil Components
- Stencil provides some syntactic sugar with TSX (JSX with TypeScript), which makes it much easier to build web components with cleaner, reduced code.
- Stencil’s compiler performs static analysis on each component to customize the build. This results in a highly optimized runtime with minimal size
- Stencil will automatically polyfill modern browser features and APIs for browsers that don’t support them.
- Stencil uses APIs built directly within the browser instead of writing custom client-side JavaScript
# Creating a Stencil Project :
Step 1: Install Stencil CLI
First, we need to set up the stencil CLI globally. Go to your terminal and run the below command:
npm install -g @stencil/core
Step 2: Create a new Stencil Project
To create a new Stencil Project, Go to the desired folder location and run the below command:
npm init stencil
When you run the above command, it will be prompted to select the project type, Please select the component and provide a project name.
? Select a starter project.
Starters marked as [community] are developed by the Stencil Community,
rather than Ionic. For more information on the Stencil Community, please see
https://github.com/stencil-community » - Use arrow-keys. Return to submit.
> component Collection of web components that can be used anywhere
app [community] Minimal starter for building a Stencil app or website
ionic-pwa [community] Ionic PWA starter with tabs layout and routes
Step 3: Install Dependencies
Navigate to your stencil project location (cd your-stencil-project
) and install the dependencies as shown below
npm install
Once the dependencies are installed, run the below command to make sure the Stencil project is running correctly.
npm start
Go to this location and check your output http://localhost:33333
Creating a Web Components :
Now let’s create a custom Web Component. For this example, we’ll create a simple Button component.
Step 1: Generating a new Component
Go to your project location in the terminal and execute the below command to generate a new component:
npm run generate
You’ll be prompted to enter the name of your component. For this article, we name the button component as “new-button”. Enter the component name and press Enter.
> my-stencil-project@0.0.1 generate
> stencil generate
[38:18.7] @stencil/core
[38:19.1] v4.22.1
√ Component tag name (dash-case): ... new-button
√ Which additional files do you want to generate? » Stylesheet (.css), Spec Test (.spec.tsx), E2E Test (.e2e.ts)
$ stencil generate new-button
The following files have been generated:
- src\components\new-button\new-button.tsx
- src\components\new-button\new-button.css
- src\components\new-button\test\new-button.spec.tsx
- src\components\new-button\test\new-button.e2e.ts
New components will be added to your project.
Step 2: Define the Component
Go to your generated component file location(src/components/new-button/new-button.tsx
) and define your component as shown below:
import { Component, h, Prop } from '@stencil/core';
@Component({
tag: 'new-button',
styleUrl: 'new-button.css',
shadow: true,
})
export class NewButton {
@Prop() text: string;
render() {
return (
<button>
{this.text}
</button>
);
}
}
Note:
@Prop
decorator lets you create parameters with access to component attributes.
Step 3: Add Styles
Add some basic styles to your component in the new-button.css
file:
button {
background-color: #0056b3;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border-radius: 4px;
}
button:hover {
background-color:#1500ffde;
}
Step 4: Build Your Component
Build your component by running:
npm run build
Step 5: Test your Component
You can test your component by adding the component name to your index.html
<new-button text="My First Component"></new-button>
Here text is the label name of your button component.
Your index.html
file looks like this:
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
<title>Stencil Component Starter</title>
<script type="module" src="/build/my-stencil-project.esm.js"></script>
<script nomodule src="/build/my-stencil-project.js"></script>
</head>
<body>
<new-button text="My Component"></new-button>
</body>
</html>
Now, run the below command and check the output in your browser (http://localhost:33333)
You can find the complete source code on GitHub
# Integrating Web Components into Angular Application
Now that our custom Web Component is built with Stencil.js, let’s integrate it into an Angular application. For this article, we are using Angular v18.
We can integrate the Stencil Web Components in different ways.
- You can publish your web component as an NPM package and configure the dependency in your angular application.
- You can manually copy and paste the web components into your angular application and configure it based on it.
- You can directly integrate your stencil project into the angular application.
In this article, We are going to integrate your stencil project directly into the angular applicaion.
Create an Angular Application
Step 1: Set Up the Environment
Go to your terminal and install the Angular command-line interface (CLI). This will help you get up and running quickly with Angular:
npm install -g @angular/cli
Step 2: Create a New Angular Project
Once Angular CLI is installed, you can use it to create a new Angular project. Navigate to the directory where you want to create your project and run the following command:
ng new stencil-angularapp --standalone=false
Step 3: Add the Stencil Project as depedency in Angular Application.
Now, We are going to add the stencil project in our Angular Application as a depedency.
Open your tsconfig.json from your angular project (stencil-angularapp) and include relative path of your Stencil Project under compilerOptions like below.
"paths": {
"@web-components/*": ["../my-stencil-project/*"]
}
Now create a folder called /libs/stencil-generated under the src folder this is where we will use the typescript path feature for keeping the stencil project as its dependency.
Now add an angular module from we will export our components inside this libs directory like below, We are creating a module calledweb-components.module.ts
We are done with the basic configuration, Now we need to configure the stencil project to copy the component into the angular application.
Adding the Angular Output Target
Go to your stencil project and Install the @stencil/angular-output-target
dependency to your Stencil component library package.
npm install @stencil/angular-output-target --save-dev
In your project’s stencil.config.ts
, add the angularOutputTarget
configuration to the outputTargets
array:
import { Config } from '@stencil/core';
// New Import
import { angularOutputTarget, ValueAccessorConfig } from '@stencil/angular-output-target';
// props binding
const angularValueAccessorBindings: ValueAccessorConfig[] = [];
export const config: Config = {
namespace: 'my-stencil-project',
outputTargets: [
{
type: 'dist',
esmLoaderPath: '../loader',
},
{
type: 'dist-custom-elements',
customElementsExportBehavior: 'auto-define-custom-elements',
externalRuntime: false,
},
{
type: 'docs-readme',
},
{
type: 'www',
serviceWorker: null, // disable service workers
},
// Newly Added Target
angularOutputTarget({
componentCorePackage: '', // Update the path
directivesProxyFile: '', // Update the path
valueAccessorConfigs: angularValueAccessorBindings,
})
],
testing: {
browserHeadless: "new",
},
};
Now update angularOutputTarget with relative paths of your angular application.
angularOutputTarget({
componentCorePackage: '@web-components/dist/components',
directivesProxyFile: './../stencil-angularapp/src/libs/stencil-generated/proxies.ts',
valueAccessorConfigs: angularValueAccessorBindings,
})
Now, build the stencil project with the following command.
npm run build
Once the build is successful you would see the stencil-generated folder in your angular application is populated with some files.
If you notice because of our tsconflg.json settings, angular is able to know what @web-components/dist/components
is referring to.
Consume the webcomponent in your Angular Application
Now we will see how to consume the webcomponents in our Application
Step 1: Registering Custom Elements
update the web-components.module.ts
with our component definition in the declarations and exports block.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
// Added for Component Rendering
import {defineCustomElements} from '@web-components/loader';
import { NewButton } from './stencil-generated/proxies';
defineCustomElements(window); // Added for rendering the component
in the browser
@NgModule({
declarations: [NewButton], // Declare the Webcomponent
imports: [
CommonModule
],
exports: [NewButton] // Ecport the Webcomponent
})
export class WebComponentsModule { }
Please note that *declareCustomElements *(not declareCustomElement) is used to initate the loader to load the custom web component , This line is very important without which the browser would render nothing.
Step2 : Update your Angular component
Now , we are going to consume the web components in our angular application module and HTML file.
Update your app.module.ts
by importing the WebComponentsModule
as shown below:
import { WebComponentsModule } from '../libs/web-components.module'; // Add webcomponent
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
WebComponentsModule // Import it here
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now update app.component.html
to consume your webcomponent.
<div class="content">
<h1>Integrating the Stencil WebComponent</h1>
<hr>
<new-button text="My First Component"></new-button>
</div>
<router-outlet />
run the angular app in dev mode
ng serve
Open http://localhost:4200
in your browser and check your webcomponent output.
You can find the complete Angular application source code on GitHub
Conclusion:
Stencil offers a powerful way to build reusable and performant components that can be easily integrated into Angular applications. If you’re looking for a solution that promotes framework independence, performance optimization, and better component reusability, Stencil is a great option to consider.
Hope this article is useful to you and your project, If you like this article, like & share it with your friends.
Follow Me for more articles.