Skip to content

giacomo/elements-template

Repository files navigation

🧩 Angular Elements Starter Kit

A modern, opinionated starter kit for building Custom Web Components (Web Components / Custom Elements) powered by Angular 21, Tailwind CSS v4, and Vitest — ready to drop into any web page or framework.

Angular Angular Elements Tailwind CSS Vitest Yarn


✨ Features

  • Dual-mode bootstrap — runs as a normal Angular app in development; compiles to a self-contained widget.js in production
  • @angular/elements — wraps Angular components as standard Custom Elements (<my-custom-widget>)
  • Shadow DOM encapsulation — components are style-isolated by default via ViewEncapsulation.ShadowDom
  • Zoneless — uses provideZonelessChangeDetection() for maximum performance and smaller bundles
  • Tailwind CSS v4 — utility-first styling included out of the box
  • Vitest — fast unit testing via the Angular CLI Vitest builder
  • Single-file outputconcat.js post-build script produces one clean dist/release/widget.js

🔧 Prerequisites

Tool Version
Node.js ≥ 20
Yarn 4 (corepack)
Angular CLI 21 (npm i -g @angular/cli)

Enable Yarn 4 via Corepack (once):

corepack enable

🚀 Getting Started

# 1. Clone the repo
git clone https://github.com/your-org/elements-template.git
cd elements-template

# 2. Install dependencies
yarn install

# 3. Start the dev preview
yarn start

Open http://localhost:4200 — you'll see the example chat widget rendered inside the Angular dev shell.


📜 Available Scripts

Script Description
yarn start Start the dev server at localhost:4200
yarn build Standard Angular production build to dist/
yarn build:wc Build the Web Component → outputs dist/release/widget.js
yarn test Run unit tests with Vitest
yarn watch Incremental dev build in watch mode

🏗️ How It Works

Dual-mode bootstrap (src/main.ts)

The entry point detects the environment flag and switches modes:

development  →  bootstrapApplication(App)      full Angular dev shell
production   →  createApplication() +
                createCustomElement(Example)   registers <my-custom-widget>
  • Dev mode boots the standard Angular app so you can iterate fast with HMR.
  • Production mode calls createApplication() (no root component) and registers each Angular component as a native Custom Element via customElements.define().

Build pipeline (yarn build:wc)

ng build --configuration production
          └─ dist/elements-template/browser/main-<hash>.js
                    ↓  concat.js
          dist/release/widget.js   ← single deployable file

concat.js locates the hashed main bundle and copies it to a stable, hash-free filename you can reference from any HTML page.


📦 Using the Widget

After running yarn build:wc, include the single output file in any HTML page — no Angular, no build tools needed on the consumer side:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>My Page</title>
</head>
<body>

  <!-- Drop the custom element anywhere on the page -->
  <my-custom-widget></my-custom-widget>

  <!-- Load the self-contained bundle -->
  <script src="path/to/widget.js"></script>

</body>
</html>

The widget is fully encapsulated — its styles live inside the Shadow DOM and will not bleed into or be affected by the host page's CSS.


🛠️ Creating a New Web Component

1. Generate the component

ng generate component components/my-widget

2. Enable Shadow DOM encapsulation

// src/app/components/my-widget/my-widget.ts
import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-my-widget',
  templateUrl: './my-widget.html',
  styleUrl: './my-widget.css',
  encapsulation: ViewEncapsulation.ShadowDom,  // ← required
})
export class MyWidget {}

3. Register it as a Custom Element (src/main.ts)

import { MyWidget } from './app/components/my-widget/my-widget';

createApplication({ providers: [provideZonelessChangeDetection()] })
  .then((appRef) => {
    customElements.define(
      'my-widget',
      createCustomElement(MyWidget, { injector: appRef.injector })
    );
  });

4. Build & ship

yarn build:wc
# → dist/release/widget.js

Tip: You can register multiple components from the same build by chaining additional customElements.define() calls inside the same .then() block.


🗂️ Project Structure

src/
├── main.ts                          # Dual-mode bootstrap
├── environments/
│   ├── environment.ts               # production: true  → Web Component mode
│   └── environment.development.ts  # production: false → Dev shell mode
└── app/
    ├── app.ts / app.html            # Dev-only shell (not part of the WC build)
    └── components/
        └── example/                 # Sample chat widget component
            ├── example.ts           # ViewEncapsulation.ShadowDom
            ├── example.html
            └── example.css
concat.js                            # Post-build script → dist/release/widget.js

🔑 Key Technologies

Technology Role
Angular 21 Component framework
@angular/elements Custom Elements bridge
Tailwind CSS v4 Utility-first styling
Vitest Unit test runner
Yarn 4 Package manager

📚 Resources

About

A modern, opinionated starter kit for building **Custom Web Components** (Web Components / Custom Elements) powered by **Angular 21**, **Tailwind CSS v4**, and **Vitest** — ready to drop into any web page or framework.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors