Table of Contents


Angular Elements in Non-Angular Apps: Use Angular components in React and VueJS environments

Introduction

An approach to reuse logic and UI created as a component without knowing the whole logic, helps in managing projects. Using this we can seamlessly add in non-Angular environments like React and Vue.js. It is a powerful solution to reduce re-writing code in various projects. So this can be used in today’s fast-evolving frontend ecosystem.

Prerequisites

Node.js v20.19.2

Angular cli v18.2.20

Before we begin, ensure Node.js and Angular cli is installed.

Step 1: Create a new angular application 

Run the following command to generate a new Angular app:


ng new custom-angular --no-standalone --no-routing 
cd custom-angular						
						

Note: During setup, choose the default configuration (no SSR, CSS for styling, unless otherwise needed, --no-routing is used to skip the routing configuration and --no-standalone is used to create app module).

After creation serve the project using command


npm start or ng serve		
						

Step 2: Add Bootstrap CDN Links

Add Bootstrap v5.3 using cdn links add these tags to attach css and javascript bundle files in index.html.


<!doctype html> 
<html lang="en"> 
<head> 
  <meta charset="utf-8"> 
  <title>CustomAngular</title> 
  <base href="/"> 
  <meta name="viewport" content="width=device-width, initial-scale=1"> 
  <link rel="icon" type="image/x-icon" href="favicon.ico"> 
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous"> 
</head> 
<body> 
  <app-root></app-root> 
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js" integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q" crossorigin="anonymous"></script> 
</body> 
</html>						
						

Step 3: Remove the Default App Content and create popup box

By default, Angular includes sample HTML in the AppComponent. To prepare for a custom popup element.

Additions in app.component.html


<div class="bg"></div> 
<div class="card mx-auto mt-5" style="width: 28rem;"> 
    <div class="card-body"> 
        <div>
            <h5 class="card-title">{{title}}</h5> 
            <p class="card-text">{{message}}</p> 
        </div> 
        <div class="text-end"> 
            <button class="btn btn-danger me-2" (click)="close.emit()">{{back}}</button> 
            <button class="btn btn-success" (click)="submit.emit()">{{proceed}}</button> 
        </div> 
    </div> 
</div> 						
						

Additions in app.component.css


.bg{
    height: 100vh; 
    width: 100vw; 
    background-color: rgb(0, 0, 0); 
    opacity: 0.3; 
    position: fixed; 
    top: 0; 
}						
						

Additions in app.component.ts


@Input() title: any 
@Input() message: any 
@Input() back: any 
@Input() proceed: any 
@Output() close = new EventEmitter() 
@Output() submit = new EventEmitter()						
						

Add this code in the app component to create a popup element and variables title, message, back and proceed are created to show in the popup box.

Step 4: Install angular elements

Use Angular CLI commands to install angular elements package. Open a terminal in your project directory and run the following:


Run ‘npm i @angular/elements@18.2.13’			
						

Step 5: Configure App Module

Update your app.module.ts file to define custom elements. This includes default declarations and imports. Add a constructor in AppModule.


import { Injector, NgModule } from '@angular/core'; 
import { BrowserModule } from '@angular/platform-browser'; 
import { createCustomElement } from '@angular/elements'; 
import { AppComponent } from './app.component'; 
@NgModule({
  declarations: [ 
    AppComponent 
  ], 
  imports: [ 
    BrowserModule 
  ] 
}) 
export class AppModule { 
   constructor(private injector:Injector){ 
        const popupBox = createCustomElement(AppComponent, {injector}) 
        customElements.define('popup-box', popupBox) 
    } 
    ngDoBootstrap(){} 
}	
						

Now add the popup-box tag in index.html.

Modifications in index.html


<body> 
    <popup-box message="Do you want to delete?" title="Delete confirmation" back="Cancel" proceed="Yes, Delete it?" (close)="close()" (submit)="submit()"></popup-box> 
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js" integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q" crossorigin="anonymous"></script> 
</body>						
						

The popup element looks like:

Step 6: Create build of Angular project.

Create the build of angular project using the command


Run ‘ng build -configuration production’						
						

This will create a dist folder in the app directory and inside its dist-> custom-angular -> browser folder main.js and polyfills.js will be created to be used in Reactjs and VueJs projects as mentioned below.

Step 7: Setup of React Project

Create a new react app to implement angular elements in React. Using Vite create a new react app by command


Run ‘npm create vite’						
						

After running this command choose yes to proceed, add project name, select framework as React, variant as Javascript and run the commands provided after it.

Run the commands to proceed further


Run ‘cd custom-reactjs’ 
Run ‘npm install’ 
Run ‘npm run dev’
						

Remove the styling from index.css and App.css. Also remove the default design from App.jsx.

Step 8: Add Bootstrap CDN Links and main and polyfills in react app

Add Bootstrap v5.3 using CDN links add these tags to attach css and javascript bundle files, and main.js and polyfills.js from angular dist. Create a folder named ang in the public folder and add the files in it.


<!doctype html> 
<html lang="en"> 
<head> 
  <meta charset="UTF-8" /> 
  <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 
  <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
  <title>Vite + React</title> 
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous"> 
</head> 
<body> 
  <div id="root"></div> 
  <script type="module" src="/src/main.jsx"></script> 
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js" integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q" 
  crossorigin="anonymous"></script> 
  <script type="module" src="/public/ang/main-ISKHZCKT.js"></script> 
  <script src="/public/ang/polyfills-FFHMD2TL.js"></script> 
</body> 
</html>						
						

Step 9: Creating a sample in Layout component

Now let’s start working on the layout component. Create a Layout.jsx and the following code in it.

On click on the button open modal by showing and on click of close and submit hide the popup again.

Additions in Layout.jsx


import { useRef, useState } from "react"; 
function Layout() { 
    const [isModelOpen, SetModelStatus] = useState(false); 
    const popRef = useRef(); 
    const closeFun = () => { 
        SetModelStatus(false); 
    } 
    const openFun = () => { 
        SetModelStatus(true); 
        setTimeout(() => { 
            let elCurrent = popRef.current 
            if (elCurrent) { 
                elCurrent.addEventListener('close', closeFun); 
                elCurrent.addEventListener('submit', closeFun); 
            } 
        }, 100) 
    } 
    return ( 
        <> 
            <div className="py-5 container"> 
                <button className="btn btn-primary" onClick={openFun}>Open Popup</button> 
            </div> 
            {isModelOpen ? 
                <popup-box message={"Do you want to delete?"} title={"Delete confirmation"} back={"Cancel"} proceed={"Yes, Delete it?"} ref={popRef}></popup-box> 
                : ''} 
        </> 
    )
} 
export default Layout;						
						

Modifications in App.jsx


import './App.css'; 
import Layout from './Layout'; 
function App() { 
  return ( 
    <> 
      <Layout /> 
    </> 
  ) 
}; 
export default App; 						
						

The output looks like

Step 10: Setup of VueJs Project

Create a new vue.js app to implement angular elements in VueJs. Using Vite create a new vue app by command


Run ‘npm create vite’						
						

After running this command choose yes to proceed, add project name, select framework as Vue, variant as Javascript and run the commands provided after it.

Run the commands to proceed further


Run ‘cd custom-vuejs’ 
Run ‘npm install’				
Run ‘npm run dev’		
						

Remove the styling from style.css. Also remove the default design from App.vue.

Step 11: Add Bootstrap CDN Links and main and polyfills in vue js app

Add Bootstrap v5.3 using CDN links add these tags to attach css and javascript bundle files, and main.js and polyfills.js from angular dist. Create a folder named ang in the public folder and add the files in it.


<!DOCTYPE html> 
<html lang=""> 
  <head> 
    <meta charset="UTF-8"> 
    <link rel="icon" href="/favicon.ico"> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
    <title>Vite App</title> 
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous"> 
  </head> 
  <body> 
    <div id="app"></div> 
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js" integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q" crossorigin="anonymous"></script> 
    <script type="module" src="/src/main.js"></script> 
    <script type="module" src="/public/ang/main-ISKHZCKT.js"></script> 
	<script src="/public/ang/polyfills-FFHMD2TL.js"></script> 
  </body> 
</html>						
						

Step 12: Creating a sample in Layout component

Now let’s start working on the layout component. Create a Layout.vue in components folder and the following code in it.

On click on the button open modal by showing and on click of close and submit hide the popup again.

Additions in Layout.vue


<script setup> 
    import {ref, nextTick} from 'vue' 
    const isModelOpen = ref(false) 
    const popRef = ref(null) 
    function change(){ 
      isModelOpen.value = !isModelOpen.value 
      nextTick(() => { 
        if(isModelOpen.value){ 
          popRef.value.addEventListener('close',change); 
          popRef.value.addEventListener('submit',change); 
        } 
      }) 
    } 
</script> 
<template> 
  <div class="py-5 container"> 
    <button class="btn btn-primary" @click="change()">Open Popup</button> 
  </div> 
  <popup-box v-if="isModelOpen" message="Do you want to delete?" title="Delete confirmation" back="Cancel" proceed="Yes, Delete it?" ref="popRef"></popup-box> 
</template> 
<style scoped> 
</style>						
						

Modifications in App.vue


<script setup> 
import Layout from './components/Layout.vue'; 
</script> 
<template> 
    <Layout/> 
</template>						
						

The output looks like

Conclusion :

This unlocks a new feature to collaborate across framework boundaries without affecting performance. To export a standard web component and use angular for that, we can achieve a framework based component model to reduce efforts in development. To ensure the consistency in UI it is important to load angular scripts correctly, handling event bindings which provides reusability in frontend frameworks.

Ready to Build Something Amazing?

Get in touch with Prishusoft – your trusted partner for custom software development. Whether you need a powerful web application or a sleek mobile app, our expert team is here to turn your ideas into reality.

image