Featured resource
Tech Upskilling Playbook 2025
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Learn more
  • Labs icon Lab
  • Core Tech
Labs

Guided: Web Components Framework Integration

Modern apps demand flexible UI solutions. In this Code Lab, you’ll refactor a React task manager to integrate Web Components — bridging framework boundaries for reusable, scalable UIs. You'll tackle real-world challenges: syncing state bidirectionally, handling component lifecycles, and avoiding memory leaks.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 48m
Last updated
Clock icon Aug 15, 2025

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    Welcome to the lab Guided: Web Components Framework Integration.

    In this Code Lab, you will assume the role of a software developer tasked with integrating a Web Component into an existing Task Manager application that has been built with React. Through the course of this lab you will learn how to:

    • Integrate a Web Component into a React component.
    • Use HTML attributes to pass string data to Web Components.
    • Pass complex data structures from a React component to a Web Component.
    • Pass data from a Web Component to a React component.

    Task Manager Application

    The application that you'll be working with includes the following files:

    • index.html: The entrypoint for the app, which loads the the React application JavaScript.
    • src/main.jsx: Handles rendering of the React application.
    • src/index.css: Basic styles for the application.
    • src/App.jsx: A task manager component implemented with React. It implements functionality for creating, completing and deleting tasks.
    • src/App.css: Styles for the React App component.
    • src/task-item.js: A Web Component that renders the UI for a single task: a checkbox, the text for the task, a delete button. This component is not yet integrated into the React application.

    The application has been configured with the Vite build tool. This provide React transpilation and a development server.

    How to Work On Tasks

    The tasks in this lab will instruct you to make changes in the App.jsx and task-item.js files. These files are already open and ready for you to work with in the code editor.

    While you are working on a task you can preview your changes to the application. On the Terminal tab, click the Run button. Once the development server has started, switch to the Web Browser tab and click the Refresh button on the left to load the Task Manager app.

    Whenever you make changes in App.jsx or task-item.js you will need to stop the development server in the Terminal by pressing Ctrl + C on your keyboard, then click the Run button again, switch to the Web Browser tab and click the Refresh button.

    Checking Your Work

    To check your work for a task, click the Validate button above the task steps. This will run tests against your code and let you know if there's anything that you need to change.

    The solutions for each task can be found in the solution directory in the Filetree.

  2. Challenge

    Integrate a Web Component

    Component Lifecycles

    The lifecycle of React components is state centric, whereas the lifecycle of Web Components is Document Object Model (DOM) centric. When integrating Web Components with React components these differences manifest in the following ways:

    1. Core Lifecycle Triggers

    Web Components use native browser lifecycle callbacks, for example: connectedCallback when the component is mounted, disconnectedCallback for unmount, attributeChangedCallback for attribute updates. These callbacks are triggered by DOM mutations. React components, however, rely on a virtual DOM and scheduler driven phases: useEffect hooks for post render setup, cleanup functions for unmount, and state/prop changes triggering re-renders. React lifecycles are framework controlled and not directly tied to explicit DOM operations.

    2. Update Handling

    Web Components react only to explicit DOM changes, for example observed attribute modifications can be handled via an attributeChangedCallback callback method. Internal state changes in a Web Component don't automatically trigger re-renders unless you explicitly handle them this way. In contrast, React components re-render on every state/prop change by default, synchronizing the UI with the component's internal state through diffing and reconciliation.

    Registering and Integrating Web Components

    Web Components operate like native HTML elements once registered. By importing the Web Component's JavaScript file, the custom element (<task-item>) becomes globally available. When the file is imported, it registers the element with the browser using customElements.define(), allowing you to use the tag anywhere in your React JSX as if it were standard HTML. This allows you to bridge framework boundaries while leveraging the browser's built-in component model. You've successfully integrated a framework-agnostic Web Component into the JSX of a React component. Observe how the browser renders the custom element seamlessly alongside React components. This demonstrates the first principle of Web Component integration: custom elements behave like standard HTML tags once registered. In the next step, you'll pass data into the Web Component to make it interactive.

  3. Challenge

    Pass State with Attributes

    Web Components can receive data through HTML attributes, which are always string values. To pass React state to a Web Component with HTML attributes you must:

    1. Convert non-string values, like booleans, to strings

    This can be achieved by calling the toString method when passing the value in an HTML attribute within your React component, for example:

    <data-card status={card.status.toString()}></data-card>
    

    2. Declare observed attributes in the Web Component

    You must declare the attributes for which your element needs change notifications. This can be achieved by defining a static field named observedAttributes with an array of the attribute names, for example:

    static observedAttributes = ["name", "enabled"];
    

    3. Implement an attributeChangedCallback method to handle attribute updates

    When attributes change, the Web Component should automatically updates its internal DOM. This can be achieved by defining an attributeChangedCallback callback method which will be called whenever an observed attribute is added, modified, removed or replaced. For example:

    attributeChangedCallback(name, oldValue, newValue) {
      switch (name) {
        case "name":
          this.textElem.textContent = newValue;
          break;
        case "enabled":
          const isEnabled = newValue === "true";
          this.checkbox.checked = isEnabled;
          this.textElem.classList.toggle("enabled", isEnabled);
          break;
      }
    }
    

    This allows you to establish one-way data flow from React to the Web Component. You've established one-way data flow from React to the Web Component using attributes. The Web Component now reacts to attribute changes, displaying the task text and completion state. This pattern maintains React as the state owner while delegating UI rendering to the Web Component. Next, you'll implement bidirectional data flow by handling events from the Web Component.

  4. Challenge

    Pass State with an Object

    HTML attributes only support string values, creating limitations for complex data structures. To pass rich JavaScript objects:

    1. Use React's ref callback functionality to access Web Component instances directly (React documentation: ref callback function).
    2. Implement setter methods on Web Components to receive and use data.
    3. Pass objects without serialization/deserialization in HTML attributes.

    This approach maintains data integrity and avoids conversion overhead. Consider an example implementation of this pattern:

    Web Component implementation:

    class DataCard extends HTMLElement {
      #cardData = null;
      
      set cardData(data) {
        this.#cardData = data;
    
        // Update DOM using this.#cardData
      }
    }
    

    React integration of the data-card element using a ref callback function:

    <data-card ref={element => element.cardData = complexObject} />
    
  5. Challenge

    Pass State to React

    Web Components communicate state changes through custom events. To establish bidirectional data flow between the Web Component and React:

    1. Dispatch custom events from the Web Component with bubbles: true and composed: true to cross shadow DOM boundaries. For example:

      	this.dispatchEvent(new CustomEvent("statusChange", {
      	  detail: { id: 42 },
      	  bubbles: true,
      	  composed: true
      	}));
      
    2. Use event delegation in React for dynamic elements, using DOM-level event listeners.

    3. Leverage React's useRef and useEffect hooks for lifecycle management of the event listeners.

    Here is an example of how the event handling might look in a React component:

    const containerRef = useRef();
    
    useEffect(() => {
      const handleUpdate = (event) => setState(event.detail.value);
    
      containerRef.current.addEventListener("statusChange", handleUpdate);
      
      return () => {
        containerRef.current.removeEventListener("statusChange", handleUpdate);
      };
    }, []);
    
    return (
      <div className="container" ref={containerRef}>
    	  <data-card></data-card>
    	  <data-card></data-card>
    	  <data-card></data-card>
      </div>
    );
    

    This pattern maintains separation of concerns while enabling interaction and passing of state between the React component and the Web Component. You've established full bidirectional communication:

    • Web Components dispatch custom events with rich data payloads.
    • React handles events through delegated DOM listeners.
    • Lifecycle hooks ensure proper cleanup.

    This completes the integration pattern where React manages application state while Web Components handle UI rendering and interaction. This approach is now production-ready with efficient event handling and no memory leaks.

  6. Challenge

    Conclusion

    Congratulations! You've successfully integrated a Web Component into a React application while navigating key differences in component lifecycles and data flow patterns. In this lab, you learned:

    • How DOM-centric Web Component lifecycles (connectedCallback, attributeChangedCallback) differ from React's state-centric model (useEffect, automatic re-renders).
    • Techniques for one-way data flow via HTML attributes and observed properties.
    • Object-based data transfer using refs and setters to preserve complex structures.
    • Bidirectional communication through custom DOM events with proper cleanup.

    The application you've implemented demonstrates production-ready integration patterns where React manages application state while Web Components handle rendering and UI logic. This hybrid approach unlocks the power of browser-native components within modern frameworks.

    Experiment With Your New Skills

    1. Try adding a new dueDate attribute to <task-item> and observe how React passes date strings vs including them in an object.
    2. Modify custom event detail objects to include entire task objects instead of just IDs.
    3. Experiment with Shadow DOM encapsulation by adding additional styles inside task-item.js.

    Continue Your Learning Journey

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.