# Part 1/2: Introduction to Web Components and Cross-Framework Integration

> **Disclaimer!**
> 
> This 2-part series is not meant for a quick read—it requires you to take the time to analyze the code blocks and connect the functionality as you read through. Since **Web Components** is a distributed concept, it assumes some prior understanding of important concepts like **Events**, **Markup**, **bundlers**, and **HTML element attributes**. By diving into the details, this series aims to set a solid foundation for you to start thinking about **solutions with Web Components**, enabling you to confidently use them in your own projects.

## **Introduction to Web Components**

As front-end development continues to evolve, we’re constantly on the lookout for better ways to create reusable, maintainable, and scalable user interfaces. One of the most powerful tools in the modern web developer’s toolbox is **Web Components**.

Web Components allow us to build **custom HTML elements** that encapsulate their structure, styling, and behavior. These elements can be reused across projects, frameworks, and even different tech stacks without worrying about how they’re implemented under the hood. Whether you're working with **React**, **Angular**, **Vue**, or **plain HTML/JS**, Web Components give you the flexibility to create truly framework-agnostic, reusable components.

Let’s dive into what makes Web Components so special, starting with their key technologies.

## **What are Web Components?**

At its core, a Web Component is a custom, reusable element that behaves just like any other HTML element. The difference is that **you** define what this element looks like, how it behaves, and how it interacts with other elements. You can think of Web Components as a combination of three key technologies:

1. **Custom Elements** – Define your own HTML elements with specific behavior.
    
2. **Shadow DOM** – Encapsulate the internal structure and styles of the element, so they don’t interfere with the rest of the page.
    
3. **HTML Templates and Slots** – Provide reusable markup and allow for flexible content insertion.
    

Each of these technologies works together to create a truly isolated, reusable, and powerful component system.

## **Key Technologies Behind Web Components**

### **1\. Custom Elements**

At the heart of Web Components are **Custom Elements**. These are exactly what they sound like: elements you create yourself. You can define new HTML tags (like `<custom-button>`) and give them specific functionality, just like how you use `<button>` or `<input>`.

Here’s how you can define your own custom element:

```javascript
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = `<button>Click Me!</button>`;
  }
}

customElements.define('my-button', MyButton);
```

Now you can use `<my-button>` anywhere in your HTML, and it will render a button:

```xml
<my-button></my-button>
```

This simple example might look underwhelming, but when combined with the **Shadow DOM** and **HTML templates**, you can create fully-featured, isolated components that are reusable across projects and frameworks.

---

### **2\. Shadow DOM**

One of the trickiest things about web development is managing styles across large projects. Have you ever styled a button in one part of your app only to find that it’s broken elsewhere because of some conflicting CSS? This is where the **Shadow DOM** comes in.

The **Shadow DOM** lets you encapsulate your component’s structure and styles so they don’t affect anything outside of the component, and nothing outside can affect your component either. Think of it like an impenetrable barrier around your component’s inner workings.

Here’s how we add a **Shadow DOM** to our `MyButton` component:

```javascript
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        button {
          background-color: purple;
          color: white;
          padding: 10px;
          border: none;
          border-radius: 5px;
        }
      </style>
      <button>Click Me!</button>
    `;
  }
}

customElements.define('my-button', MyButton);
```

Now, the button inside `<my-button>` has its own style, and those styles won’t affect or be affected by any other part of your app.

#### **Illustration:**

* Without Shadow DOM, you could have a button with global styles that override its appearance.
    
* With Shadow DOM, the button’s styles are isolated. No external CSS can break the button’s design, and your component behaves consistently everywhere.
    

---

### **3\. HTML Templates and Slots**

Sometimes you need to create reusable pieces of markup within your custom elements. That’s where **HTML templates** come into play. Templates allow you to define reusable chunks of HTML that are only rendered when needed, rather than at the moment the page is loaded.

Here’s an example:

```xml
<template id="my-template">
  <style>
    p {
      color: red;
    }
  </style>
  <p>I'm inside a template!</p>
</template>

<script>
  class MyTemplate extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById('my-template');
      const templateContent = template.content.cloneNode(true);
      this.attachShadow({ mode: 'open' }).appendChild(templateContent);
    }
  }

  customElements.define('my-template', MyTemplate);
</script>
```

This `<template>` tag defines some HTML (a red paragraph in this case) that can be used inside your custom element without rendering it directly in the document. When the component is created, the content from the template is "stamped out" into the Shadow DOM.

#### **Slots: Customizable Content**

Sometimes you need part of a Web Component to be customizable. This is where **slots** come in. Slots allow you to insert content from outside the component into specific parts of its template.

```javascript
class MyCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        .card {
          border: 1px solid #ccc;
          padding: 20px;
          border-radius: 5px;
        }
      </style>
      <div class="card">
        <slot name="title"></slot>
        <p><slot></slot></p>
      </div>
    `;
  }
}

customElements.define('my-card', MyCard);
```

Here’s how you can use slots:

```xml
<my-card>
  <h3 slot="title">Card Title</h3>
  This is the content inside the card.
</my-card>
```

The **title slot** allows for the `<h3>` element to be inserted from the outside, while the default slot lets us inject other content inside the `<p>` tag. This flexibility is powerful when building reusable UI components.

## **Why Use Web Components?**

Now that we’ve gone over the basic building blocks of Web Components, you might be asking: **Why should I bother with all this? Why not just stick with React, Angular, or Vue?**

Here’s why Web Components are awesome:

1. **Framework Agnostic**: Web Components work with any JavaScript framework—or none at all. You can use them in **React**, **Angular**, **Vue**, or even in plain **HTML/JavaScript**. This makes them an ideal choice for projects with multiple tech stacks.
    
2. **Encapsulation**: Thanks to the **Shadow DOM**, your components' styles and structure are completely isolated. You never have to worry about global CSS breaking your component—or vice versa.
    
3. **Reusability**: Build a component once and reuse it across multiple projects, no matter the framework. This drastically reduces code duplication and ensures consistency across large applications.
    
4. **Future-Proof**: Web Components are part of the browser’s native APIs. They’re not tied to any framework that might go out of fashion. Your custom elements will continue to work for years to come.
    
5. **Great for Microfrontends**: If you're working in a large team with different tech stacks (e.g., React in one section, Angular in another), Web Components allow you to share UI elements across all parts of the app without having to rewrite them for each framework.
    

## **Understanding Web Components in Multi-Tech Stack Projects**

### **Building and Sharing the** `MyButton` Web Component

Let’s go through how you can create a **simple Web Component**, bundle it into a **UMD module**, and share it for use in various frameworks like **React**, **Angular**, and **Vue**. We'll also make sure it's clear **where the bundle needs to be placed** and how it can be imported and used.

#### **Step 1: Creating the** `MyButton` Component

We start by defining the Web Component in a file called `MyButton.js`:

```javascript
// MyButton.js
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        button {
          background-color: var(--button-bg-color, #007BFF);
          color: var(--button-text-color, #ffffff);
          padding: var(--button-padding, 10px 20px);
          border: none;
          border-radius: 5px;
          cursor: pointer;
        }
        button:hover {
          background-color: var(--button-hover-bg-color, #0056b3);
        }
      </style>
      <button><slot></slot></button>  <!-- Slot for dynamic content -->
    `;
  }
}

customElements.define('my-button', MyButton);
```

This component:

* Encapsulates its styles using the **Shadow DOM**.
    
* Uses **CSS custom properties** to allow customization (e.g., `--button-bg-color`, `--button-padding`).
    
* Uses a **slot** to insert dynamic content inside the button.
    

#### **Step 2: Bundling the Web Component as a UMD Module**

To make this component reusable across projects, you can bundle it using **Webpack** or **Rollup** into a **UMD (Universal Module Definition)** format. The UMD format ensures that the component can be imported in different environments (e.g., via a `<script>` tag or as a module in frameworks).

Here’s the Webpack configuration to bundle the `MyButton.js` component:

**Webpack configuration (**`webpack.config.js`):

```javascript
const path = require('path');

module.exports = {
  entry: './MyButton.js',  // Entry point for the Web Component
  output: {
    filename: 'my-button.bundle.js',  // Name of the bundled output file
    path: path.resolve(__dirname, 'dist'),  // Output directory for the bundle
    library: 'MyButton',  // Optional global variable name
    libraryTarget: 'umd',  // UMD format to work in different environments
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',  // Transpile ES6+ code for compatibility
        },
      },
    ],
  },
};
```

After configuring Webpack, you can generate the bundle by running:

```yaml
npx webpack --config webpack.config.js
```

This will create a bundled file called `my-button.bundle.js` inside a `dist` directory. This file contains your `MyButton` component in a UMD format, ready to be used in any project.

#### **Step 3: Where to Place the UMD Bundle**

Once you have generated the UMD bundle (`my-button.bundle.js`), you have several options for how to distribute and use it:

1. **Local Projects**:
    
    * Place the `my-button.bundle.js` file in your project’s `public` or `assets` folder.
        
    * You can then load it via a `<script>` tag directly in your HTML files or import it into your JavaScript modules.
        
2. **Sharing Across Teams**:
    
    * **Option 1: Publish to npm**: If you want other teams to be able to install the Web Component via a package manager, publish it to **npm**.
        
        ```yaml
        npm publish
        ```
        
        Other teams can then install it via:
        
        ```yaml
        npm install my-button
        ```
        
    * **Option 2: Host the Bundle on a CDN**: You can upload the bundle to a CDN (like **jsDelivr** or **unpkg**) so that it can be loaded directly into any project via a `<script>` tag. For example:
        
        ```xml
        <script src="https://cdn.example.com/my-button.bundle.js"></script>
        ```
        
3. **Using the Bundle in Different Frameworks**: Once the bundle is published or placed in a project's public directory, teams can use it by either importing it in JavaScript files or referencing it through a script tag.
    

---

### **Using the** `MyButton` Component Across Different Frameworks

Now that we have the **UMD bundle** (`my-button.bundle.js`), let’s see how it can be used in **React**, **Angular**, and **Vue**.

---

#### **1\. Using** `MyButton` in React

If you’ve published the component to npm, or placed the `my-button.bundle.js` in your project’s `public` directory, you can import it into your **React** application like this:

First, install the component (if published to npm):

```yaml
npm install my-button
```

Alternatively, if you’re using the `my-button.bundle.js` locally, make sure it’s placed in your project’s `public` directory, and import it directly into your React component:

```javascript
import React, { useRef, useEffect } from 'react';
import 'my-button/dist/my-button.bundle.js';  // Import the Web Component

function App() {
  const buttonRef = useRef(null);

  useEffect(() => {
    // Attach an event listener for button click
    buttonRef.current.addEventListener('click', () => {
      alert('Button clicked!');
    });
  }, []);

  return (
    <div>
      <h1>Using Web Components in React</h1>
      {/* Use the custom button with customizable styles */}
      <my-button ref={buttonRef} style="--button-bg-color: #28a745;">
        Click Me
      </my-button>
    </div>
  );
}

export default App;
```

In this case:

* You import the bundled Web Component (`my-button.bundle.js`) and then use it in your React component.
    
* You can pass **CSS custom properties** to customize the button’s appearance (e.g., `--button-bg-color: #28a745`).
    
* Use **refs** to access the Web Component and add event listeners (like handling button clicks).
    

---

#### **2\. Using** `MyButton` in Angular

For **Angular**, you’ll need to allow Angular to recognize custom elements by adding `CUSTOM_ELEMENTS_SCHEMA` to your module’s schema.

**Step 1: Install the Web Component**

If the component is published to npm:

```yaml
npm install my-button
```

Alternatively, if you’re using the local UMD bundle, place `my-button.bundle.js` in your project’s `src/assets` directory and load it with a `<script>` tag in your **index.html** file:

```xml
<!-- src/index.html -->
<script src="assets/my-button.bundle.js"></script>
```

**Step 2: Update Your Angular Module**

```javascript
// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],  // Allow custom elements
  bootstrap: [AppComponent]
})
export class AppModule { }
```

**Step 3: Use the Web Component in Angular Templates**

```xml
<!-- app.component.html -->
<my-button style="--button-bg-color: #dc3545;">
  Delete
</my-button>
```

---

#### **3\. Using** `MyButton` in Vue

In **Vue**, you can directly use Web Components in your templates. Just import the UMD bundle and reference the component in your Vue component.

**Step 1: Install or Reference the UMD Bundle**

* If using npm:
    
    ```yaml
    npm install my-button
    ```
    
* If you have the local bundle, place it in the `public` folder and include it in **index.html**:
    
    ```xml
    <!-- index.html -->
    <script src="public/my-button.bundle.js"></script>
    ```
    

**Step 2: Use** `MyButton` in Vue

```xml
<template>
  <div>
    <h1>Using Web Components in Vue</h1>
    <my-button style="--button-bg-color: #ffc107;">
      Warning
    </my-button>
  </div>
</template>

<script>
import 'my-button/dist/my-button.bundle.js';  // Import the Web Component

export default {
  name: 'App'
};
</script>
```

---

### **Handling Customization with CSS Custom Properties**

**CSS custom properties** (CSS variables) make it easy to allow teams to customize your Web Component without modifying its internal code. In our `MyButton` component, you can control the button’s background color, text color, padding, and hover effect using these properties.

For example, in any framework, you can use the Web Component like this:

```xml
<my-button style="--button-bg-color: #007bff; --button-text-color: white;">
  Submit
</my-button>
```

This approach lets teams adapt the button to match their own style guides while ensuring the underlying logic remains consistent across projects.

## **Integrating Web Components into React Applications**

Although Web Components are **framework-agnostic** and can be used across many different platforms, there are some specific details you need to consider when using them inside a **React** application. React and Web Components operate differently in certain areas, like **attributes**, **state management**, and **event handling**. In this section, we'll walk through how to integrate Web Components seamlessly into your React apps.

---

### **How Web Component Registration Works**

At the heart of Web Components is the **Custom Elements API**, which allows developers to define new HTML elements and register them with the browser. The browser then treats these custom elements as native HTML tags.

To register a Web Component, you use the `customElements.define()` method, which associates a custom element name (like `<my-button>`) with a class that defines its behavior.

For example, here's how we register a simple `MyButton` Web Component:

```javascript
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <button>Click Me!</button>
    `;
  }
}

customElements.define('my-button', MyButton);
```

Once the component is defined and registered, the browser recognizes `<my-button>` as a valid HTML element, and you can use it in any HTML file, just like a standard `<div>` or `<button>`.

But **React** works a bit differently, so we need to know how these two systems interact.

---

### **Why Do You Still Need to Import Web Components in React?**

When working with Web Components in React, there’s a key step that can be easy to overlook: **you still need to import or include the file where the Web Component is defined**. Even though Web Components are registered globally with `customElements.define()`, the **registration code** itself must be **executed** before React can use the component.

In simpler terms: even if `<my-button>` is a valid custom element, React has no idea what it is until the file containing the Web Component’s registration (`customElements.define()`) is loaded. That’s why you need to import the file or include it via a `<script>` tag.

For example:

```javascript
import './MyButton.js';  // Import the Web Component

function App() {
  return (
    <div>
      <h1>Using Web Components in React</h1>
      <my-button></my-button>  {/* React will know this element only if it's been registered */}
    </div>
  );
}

export default App;
```

Without the import, React would render `<my-button>` as an unstyled, inert HTML tag, because the browser wouldn’t know how to handle it.

---

### **Using Web Components in React: Practical Example**

Let’s take a look at a practical example of using a **Web Component** in a React application. We’ll use the **MyButton** Web Component that we’ve defined earlier.

#### **Step 1: Define the Web Component (**`MyButton.js`)

```javascript
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        button {
          background-color: #007BFF;
          color: white;
          padding: 10px 20px;
          border: none;
          border-radius: 5px;
        }
      </style>
      <button>Click Me!</button>
    `;
  }
}

customElements.define('my-button', MyButton);
```

#### **Step 2: Use the Web Component in a React App**

```javascript
import React from 'react';
import './MyButton.js';  // Import the Web Component definition

function App() {
  return (
    <div>
      <h1>Using Web Components in React</h1>
      <my-button></my-button>  {/* Now React knows about <my-button> */}
    </div>
  );
}

export default App;
```

In this example:

* The Web Component (`<my-button>`) is rendered inside a React component.
    
* The **custom element** is recognized because it has been registered and imported in `MyButton.js`.
    

---

### **Handling Web Component Attributes in React**

In React, we typically pass data to components via **props**. However, Web Components don’t have the same prop system. Instead, they interact with the DOM through **attributes** (e.g., `setAttribute()`) and **properties**.

#### **Why React Doesn't Automatically Map Props to Web Component Attributes**

React handles props differently than the DOM handles attributes. While native DOM elements (like `<input>`) automatically map props to attributes, React doesn't do this for custom elements (like `<my-button>`). This means that if you pass a prop to a Web Component, it won’t automatically appear as an attribute.

To pass values to Web Components, we need to **explicitly set the attributes** using **refs** or directly interacting with the DOM API.

---

### **Setting Attributes with React Refs**

To set attributes on a Web Component from React, we can use **React refs**. A **ref** allows us to directly access the DOM node and call methods or set attributes on it.

Here’s an example where we dynamically set an attribute on the `MyButton` Web Component:

```javascript
import React, { useEffect, useRef } from 'react';
import './MyButton.js';  // Import the Web Component

function App() {
  const buttonRef = useRef(null);  // Create a ref to access the Web Component

  useEffect(() => {
    if (buttonRef.current) {
      buttonRef.current.setAttribute('label', 'Click Me!');  // Set the 'label' attribute
    }
  }, []);

  return (
    <div>
      <h1>Passing Attributes to Web Components in React</h1>
      <my-button ref={buttonRef}></my-button>  {/* Use the ref to interact with the component */}
    </div>
  );
}

export default App;
```

In this example:

* We use `useRef` to get a reference to the Web Component.
    
* Inside `useEffect()`, we use `setAttribute()` to set the `label` attribute on the Web Component.
    

---

### **Example: Passing React State to Web Components**

React state doesn’t directly map to Web Component attributes, but we can update the attributes of a Web Component whenever the state changes. Let’s see how we can pass React state to a Web Component by updating its attributes dynamically.

```javascript
import React, { useState, useEffect, useRef } from 'react';
import './MyButton.js';  // Import the Web Component

function App() {
  const [label, setLabel] = useState('Initial Label');
  const buttonRef = useRef(null);

  useEffect(() => {
    if (buttonRef.current) {
      buttonRef.current.setAttribute('label', label);  // Set the Web Component's label attribute
    }
  }, [label]);  // Run useEffect whenever 'label' state changes

  return (
    <div>
      <h1>Passing React State to Web Components</h1>
      <input
        type="text"
        value={label}
        onChange={(e) => setLabel(e.target.value)}
        placeholder="Enter button label"
      />
      <my-button ref={buttonRef}></my-button>  {/* Ref used to interact with the Web Component */}
    </div>
  );
}

export default App;
```

Here’s what happens:

* React **state** (`label`) is updated when the user types in the input.
    
* Using the **ref**, we update the Web Component’s `label` attribute dynamically each time the state changes.
    

---

### **Handling Events Between Web Components and React**

Web Components can dispatch custom events, just like native DOM elements emit events such as `click` or `change`. To capture these custom events in React, we need to add event listeners directly to the Web Component using **refs**.

React’s synthetic event system does not automatically capture custom events emitted from Web Components, so we need to rely on the standard `addEventListener()` method.

---

### **Listening to Custom Events in React Using Refs**

Let’s modify our Web Component to emit a custom event when the button is clicked:

```javascript
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <button>Click Me!</button>
    `;

    this.shadowRoot.querySelector('button').addEventListener('click', () => {
      const event = new CustomEvent('buttonClicked', {
        detail: { message: 'Button was clicked!' },
        bubbles: true,
        composed: true
      });
      this.dispatchEvent(event);
    });
  }
}

customElements.define('my-button', MyButton);
```

This Web Component emits a `buttonClicked` event with a custom message when the button is clicked.

Now, in the React app, we can capture that custom event:

```javascript
import React, { useEffect, useRef } from 'react';
import './MyButton.js';  // Import the Web Component

function App() {
  const buttonRef = useRef(null);

  useEffect(() => {
    if (buttonRef.current) {
      // Listen for the custom event 'buttonClicked'
      const handleClick = (event) => {
        alert(event.detail.message);  // Display the message from the event's detail
      };
      buttonRef.current.addEventListener('buttonClicked', handleClick);

      // Clean up the event listener when the component unmounts
      return () => {
        buttonRef.current.removeEventListener('buttonClicked', handleClick);
      };
    }
  }, []);

  return (
    <div>
      <h1>Handling Custom Events from Web Components in React</h1>
      <my-button ref={buttonRef}></my-button>  {/* Capture the custom event using ref */}
    </div>
  );
}

export default App;
```

Here’s what’s happening:

* We attach an event listener for the custom event `buttonClicked` using `addEventListener`.
    
* When the Web Component emits the event, we handle it by showing an alert with the event’s custom message (`event.detail.message`).
    
* We also **clean up** the event listener by removing it in the **return function** of the `useEffect` hook to prevent memory leaks.
    

---

### **Example: Two-Way Data Binding Between React and Web Components**

We’ve seen how React can pass data to Web Components using attributes and how Web Components can send data back to React using custom events. To create **two-way data binding** between React and Web Components, we can combine these approaches.

Here’s an example where:

1. React passes data (a label) to the Web Component.
    
2. The Web Component sends a custom event back to React when its internal state changes (e.g., when the button is clicked).
    

#### **Step 1: Modify the Web Component to Handle Two-Way Data Binding**

Let’s extend our `MyButton` Web Component to handle dynamic content and emit a custom event when clicked:

```javascript
class MyButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        button {
          background-color: #007BFF;
          color: white;
          padding: 10px 20px;
          border: none;
          border-radius: 5px;
        }
      </style>
      <button><slot></slot></button>  <!-- Slot to allow dynamic content -->
    `;

    this.shadowRoot.querySelector('button').addEventListener('click', () => {
      const event = new CustomEvent('buttonClicked', {
        detail: { message: 'Button was clicked!' },
        bubbles: true,
        composed: true
      });
      this.dispatchEvent(event);  // Emit a custom event when the button is clicked
    });
  }
}

customElements.define('my-button', MyButton);
```

#### **Step 2: Two-Way Data Binding in React**

Now let’s create the React side, where we’ll:

* Pass a label from React to the Web Component.
    
* Listen for a custom event from the Web Component and update React state based on that event.
    

```javascript
import React, { useState, useEffect, useRef } from 'react';
import './MyButton.js';  // Import the Web Component

function App() {
  const [buttonLabel, setButtonLabel] = useState('Click Me!');
  const [message, setMessage] = useState('');
  const buttonRef = useRef(null);

  useEffect(() => {
    if (buttonRef.current) {
      // Set the initial label of the button via the 'slot' content
      buttonRef.current.innerHTML = buttonLabel;

      // Listen for the custom 'buttonClicked' event
      const handleClick = (event) => {
        setMessage(event.detail.message);  // Update React state when event is received
      };
      buttonRef.current.addEventListener('buttonClicked', handleClick);

      // Cleanup the event listener on component unmount
      return () => {
        buttonRef.current.removeEventListener('buttonClicked', handleClick);
      };
    }
  }, [buttonLabel]);  // Update button label when state changes

  return (
    <div>
      <h1>Two-Way Data Binding Between React and Web Components</h1>
      
      <input
        type="text"
        value={buttonLabel}
        onChange={(e) => setButtonLabel(e.target.value)}  // Update button label based on input
        placeholder="Enter button label"
      />
      
      <my-button ref={buttonRef}></my-button>  {/* Dynamically set the button label */}

      {message && <p>{message}</p>}  {/* Display the message from the Web Component */}
    </div>
  );
}

export default App;
```

#### **What’s happening here:**

* **Passing Data to the Web Component**: We update the `innerHTML` of the Web Component (using a **slot**) to reflect the current state of the `buttonLabel` in React. This way, when the user types in the input, the Web Component’s label updates in real time.
    
* **Receiving Data from the Web Component**: When the button inside the Web Component is clicked, it emits a `buttonClicked` custom event. We listen for this event using **refs** and update the React state (`message`), displaying the message on the screen.
    

This approach creates a **two-way binding** where:

* **React passes data to the Web Component** (the button label).
    
* **The Web Component sends data back to React** (via the custom event when the button is clicked).
    

### **Conclusion for Part 1**

Web Components have revolutionized how we think about building and sharing UI components across multiple frameworks. By offering encapsulation, reusability, and framework-agnostic capabilities, they empower developers to create more flexible, maintainable systems. In this part of the blog, we laid the groundwork for understanding how Web Components can be integrated into React applications and shared across different tech stacks, providing practical examples and clear insights.

In **Part 2**, we’ll take things to the next level by diving into advanced usage patterns for Web Components in large-scale applications.
