<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Valkoivo</title>
    <description>The latest articles on DEV Community by Valkoivo (@valkoivo).</description>
    <link>https://dev.to/valkoivo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2681252%2F59047773-f337-435d-aacc-98214fa1c48a.jpg</url>
      <title>DEV Community: Valkoivo</title>
      <link>https://dev.to/valkoivo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/valkoivo"/>
    <language>en</language>
    <item>
      <title>An Example of Data Exchange Between Web Components</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Thu, 13 Feb 2025 17:02:44 +0000</pubDate>
      <link>https://dev.to/valkoivo/an-example-of-data-exchange-between-web-components-3b1h</link>
      <guid>https://dev.to/valkoivo/an-example-of-data-exchange-between-web-components-3b1h</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/valkoivo/handshake-between-web-components-23ge"&gt;previous articles&lt;/a&gt;, I devoted significant attention to the theoretical aspects related to organizing the interaction of web components. We thoroughly examined various approaches to building architecture, discussed potential challenges, and explored ways to overcome them. One of the key points was ensuring a convenient and flexible method for creating web components in such a way that they could be easily integrated into a project or tested in an isolated environment with minimal effort.&lt;/p&gt;

&lt;p&gt;Now that the theoretical foundation has been established, it's time to move from theory to practice. In this article, I will attempt to implement a web component that can connect to other components and receive data from them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Examine the Data Source
&lt;/h2&gt;

&lt;p&gt;Before we start creating our web component, it's essential to carefully consider what kind of data source it will interact with. This data source can be almost any existing web component, regardless of its purpose or internal implementation.&lt;/p&gt;

&lt;p&gt;Let’s assume that this component wasn’t developed by you. This imposes certain limitations and naturally creates a desire to minimize interference with its source code. Ideally, you wouldn’t want to waste time delving deeply into someone else's logic, rewriting it, or adapting it to your needs.&lt;/p&gt;

&lt;p&gt;What does this imply? First of all, the data source must be as isolated as possible from the data recipient. It shouldn’t know anything about the entities that will connect to it, nor should it be required to support any specific data transfer protocols. When it was created, the developers might not have envisioned that it would ever be used to provide data to external components.&lt;/p&gt;

&lt;p&gt;Nevertheless, despite these limitations, we still have basic requirements for the data source. First and foremost, it must &lt;a href="https://dev.to/valkoivo/methods-for-initializing-web-components-with-external-data-4de1"&gt;contain the data&lt;/a&gt; we want to use. Let’s assume it’s some object with data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;my-provider&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-provider&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some initial value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, this implementation is not sufficient. If we want the data source to not only exist but also actively notify about changes, we need to implement an event-triggering mechanism. This approach will turn the component into a proactive source, responding to data changes.&lt;/p&gt;

&lt;p&gt;It’s important to note that if the data source was created without our involvement, any events it may generate were likely not intended to notify external recipients. Most often, such events are designed for the internal purposes of the component itself, such as updating its visual state. However, for our needs, this doesn’t matter — what’s important is simply the existence of an event signaling a change in data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some initial value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_createEvent&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-provider-data-changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_announceDataReady&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_announceDataChanged&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_createEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_announceDataReady&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_announceDataChanged&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And yet, something is missing. The data source should provide a way to retrieve data, but the original component developer did not implement such an interface. This creates some inconvenience, but fortunately, we can fix the situation without modifying the original code.&lt;/p&gt;

&lt;p&gt;To do this, we will create our own subclass that extends the existing component and adds the necessary method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-provider&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-provider&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomInterfaceExposable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;retrieveDataObject&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CustomInterfaceExposable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyCustomProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, we can consider the data source ready for use. We have successfully adapted the third-party component to meet the needs of our project by adding just one method with a name that was already known to us. Now, this method will be used to access the data object, which is the core value for us.&lt;/p&gt;

&lt;p&gt;Note: It is important that we are well-acquainted with the interface of the data object itself, as this is what we will be working with, without being distracted by the behavior specifics of the data source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Receiver
&lt;/h2&gt;

&lt;p&gt;Now that we have defined the data source and adapted it to our needs, it’s time to consider the second key element — the data receiver. This is the component we will be creating. Its primary task is to receive data from the source using a unified interface, which will provide flexibility and standardization across the project.&lt;/p&gt;

&lt;p&gt;In other words, the interface implemented in the data source must be supported in the receiver as well. This ensures that the receiver can correctly interact with any source that conforms to this interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomInterfaceConsumable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;_retrieveProviderDataObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieveDataObject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyConsumer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CustomInterfaceConsumable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Another initial value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The consumer is changed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One key consideration when developing the data receiver is the freedom of its placement within the DOM structure. Why is this important? The fact is that the DOM structure is often developed by a separate specialist — a layout designer — and we don’t want to impose rigid placement requirements on them. This would add unnecessary restrictions and complicate the overall development process.&lt;/p&gt;

&lt;p&gt;Our goal is to ensure that the connection between the data source and receiver doesn’t depend on their relative positioning in the DOM tree. Ideally, the receiver can be placed anywhere: inside the source, outside it, on the same nesting level, or deeper. Furthermore, we want to support the ability to connect multiple receivers to a single source. To achieve this flexibility, we will use an identifier-based connection mechanism.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-provider&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"first_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-provider&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-consumer&lt;/span&gt; &lt;span class="na"&gt;provider_id=&lt;/span&gt;&lt;span class="s"&gt;"first_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-consumer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-consumer&lt;/span&gt; &lt;span class="na"&gt;provider_id=&lt;/span&gt;&lt;span class="s"&gt;"first_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-consumer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-consumer&lt;/span&gt; &lt;span class="na"&gt;provider_id=&lt;/span&gt;&lt;span class="s"&gt;"first_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-consumer&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;my-consumer&lt;/span&gt; &lt;span class="na"&gt;provider_id=&lt;/span&gt;&lt;span class="s"&gt;"second_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;my-provider&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"second_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-provider&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-consumer&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;my-provider&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"third_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;my-consumer&lt;/span&gt; &lt;span class="na"&gt;provider_id=&lt;/span&gt;&lt;span class="s"&gt;"third_provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-consumer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-provider&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As seen in the example, the data receiver can be either at the same level as the source, inside it, or vice versa — the source can be contained within the receiver’s structure. By using identifiers, all receivers can easily find the appropriate source and retrieve data from it.&lt;/p&gt;

&lt;p&gt;As we mentioned in the previous article, simply passing the identifier is not enough. We need the receiver not only to store the source’s identifier but also to be able to convert it into a direct reference to the data source itself. Without this, interaction would be impossible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It’s important that the behavior we implement is universal. We want to create a mechanism that can be applied to any component, turning it into a data receiver without making complex changes to its internal code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ProviderConnectable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;provider_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_identifyProvider&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_onProviderIdentified&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_identifyProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider_id&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider_id&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_onProviderIdentified&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something to initialize&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyConsumer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CustomInterfaceConsumable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;ProviderConnectable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;_onProviderIdentified&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_retrieveProviderDataObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Check for Initialization
&lt;/h2&gt;

&lt;p&gt;When working with web components, a common problem arises: the initialization of the data source and receiver doesn’t always happen synchronously. It’s entirely possible that by the time the receiver is initialized, the source may not be ready yet. Although the receiver can obtain a reference to the source, the object itself might not have the necessary methods, such as retrieveDataObject. This can lead to errors or incorrect behavior in the application.&lt;/p&gt;

&lt;p&gt;To avoid such situations, we need to implement a universal mechanism to check the readiness of the data source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ProviderConnectable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nf"&gt;_isProviderReady&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyConsumer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CustomInterfaceConsumable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;ProviderConnectable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nf"&gt;_onProviderIdentified&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_isProviderReady&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_retrieveProviderDataObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this approach only masks the problem, hiding the initialization error. We need to do more than just check the source's readiness — we must ensure correct interaction when initialization happens at different times. It’s important not only to determine readiness but also to organize a mechanism in which the receiver can wait for the source to be ready.&lt;/p&gt;

&lt;p&gt;From the source code, we know that when initialization is complete, it triggers an event. By using this, we can create a universal notification mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Type Identifier
&lt;/h2&gt;

&lt;p&gt;For the data receiver to correctly respond to the event signaling the completion of the data source initialization, it’s not enough to simply subscribe it to the event. The receiver must know exactly which event it needs to react to.&lt;/p&gt;

&lt;p&gt;The main problem is that the receiver cannot know in advance the event identifier for the event that signals the completion of the data source initialization. If the data source is not yet initialized, it naturally cannot provide methods or properties to retrieve the event identifier. This creates a circular dependency: the receiver needs the event identifier to subscribe to it, but it can only obtain it from the already initialized source.&lt;/p&gt;

&lt;p&gt;The most universal and straightforward solution is to pass the event identifier through a component attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ProviderConnectable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider_event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;provider_event&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_subscribeToProviderEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;disconnectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_unsubscribeFromProviderEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_subscribeToProviderEvent&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onProviderDataChangedBinded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onProviderDataChanged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onProviderDataChangedBinded&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_unsubscribeFromProviderEvent&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onProviderDataChangedBinded&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_onProviderDataChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something with changed data&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, the component declaration in the DOM will look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-provider&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"provider_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-provider&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-consumer&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"consumer_id"&lt;/span&gt; &lt;span class="na"&gt;provider_id=&lt;/span&gt;&lt;span class="s"&gt;"provider_id"&lt;/span&gt; &lt;span class="na"&gt;provider_event=&lt;/span&gt;&lt;span class="s"&gt;"my-provider-data-changed"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-consumer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handlers
&lt;/h2&gt;

&lt;p&gt;After we’ve created the behavior for the components, which universally links them together and allows them to be easily and declaratively declared in the DOM, there’s just one important task left — enabling the receiver to use the data provided by the source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyConsumer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CustomInterfaceConsumable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;ProviderConnectable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Another initial value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_onProviderIdentified&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_isProviderReady&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_retrieveProviderDataObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;_onProviderDataChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_isProviderReady&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_retrieveProviderDataObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The consumer is changed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, our behavior gives the component the ability to implement two event handlers, inside which it gets a reference to the data object of the source, and all subsequent work is done with this data object. This is exactly what we were aiming for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have now completed the development of a mechanism that makes it easy and efficient to connect any component to a data source. We’ve created a behavior that can be applied to any web component element to allow it to integrate with other components acting as data sources. This solution offers several key advantages.&lt;/p&gt;

&lt;p&gt;First, thanks to this behavior, the component can connect to the data source without needing to modify the JavaScript code itself. That is, we don't restrict the developer in creating components and integrating them into the project. This approach avoids unnecessary dependency on a specific implementation and provides flexibility in using the component. The component easily adapts to external conditions and can be embedded in the project without additional effort.&lt;/p&gt;

&lt;p&gt;Second, the component can be declared both declaratively and dynamically. This means we can use standard HTML markup to define the relationships between components or create components on the fly using JavaScript, depending on the needs of the project.&lt;/p&gt;

&lt;p&gt;Additionally, the solution we developed does not require changes to the DOM structure. Components can be placed anywhere within the DOM tree, whether near the data source or in another part of the document. This is an important advantage, as DOM structures are often built with various layout and interface requirements in mind, and we don’t want to restrict component placement.&lt;/p&gt;

&lt;p&gt;What’s more important, our approach allows components to work independently of the order in which they are initialized. The data source and receiver can be initialized in any order, and the system will always work correctly, ensuring a reliable connection between the components, even if the data source isn’t ready yet while the receiver is already initialized.&lt;/p&gt;

&lt;p&gt;To ensure the stability and functionality of this approach, you can test it in a live example available on the JSFiddle platform at the following link:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jsfiddle.net/valkoivo/8Ltwvkpb/9/" rel="noopener noreferrer"&gt;JSFiddle Web Components Data Exchange&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This approach is used within the KoiCom library, which I developed specifically to simplify the creation of user interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;KoiCom documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;KoiCom github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The library provides a set of tools for quick and efficient work with web components, enabling developers to easily build interactions between various parts of the interface while minimizing the amount of code and effort required to set up the system.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Handshake Between Web Components</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Fri, 07 Feb 2025 23:56:29 +0000</pubDate>
      <link>https://dev.to/valkoivo/handshake-between-web-components-23ge</link>
      <guid>https://dev.to/valkoivo/handshake-between-web-components-23ge</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/valkoivo/methods-for-initializing-web-components-with-external-data-4de1"&gt;previous article&lt;/a&gt;, we made an important assumption: if the environment initializing a web component does not need to understand the structure of the transmitted data, it can simply link two components by passing the recipient the identifier of the source. This approach reduces coupling and makes the system more flexible.&lt;/p&gt;

&lt;p&gt;However, this raises two more questions. First, are there any ways to avoid passing an identifier altogether? Second, how can a web component that receives a source identifier connect to the source itself? Let's try to answer them. As always, I promise it will be sufficiently tedious.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does It Mean to Link Two Web Components?
&lt;/h2&gt;

&lt;p&gt;Linking two web components means establishing interaction between them, allowing them to exchange data or events.&lt;/p&gt;

&lt;p&gt;For two web components to be linked, they must exist within the same environment where their accessibility is not restricted. This means that the components should either be in the same DOM scope or use mechanisms that allow them to bypass boundaries between different nesting levels. For example, if one component exists in the global DOM and the other is placed inside a Shadow DOM, direct access between them is impossible without using special APIs.&lt;/p&gt;

&lt;p&gt;What other conditions must be met for two web components to interact effectively? It is crucial that their method of communication is predefined and agreed upon in advance. In other words, both components must understand the rules for exchanging data and events and follow the same logic for transmitting information. This can be achieved through custom events, property or attribute changes, the use of a global context, or the implementation of a dedicated state manager. If one component expects data to be transmitted in one way while the other provides it in a different way, the interaction will either not occur at all or result in incorrect system behavior.&lt;/p&gt;

&lt;p&gt;The state of the components must be predictable. The data source should ensure that the information is available when requested, while the recipient must account for potential delays or the absence of data at the moment of the request. This is especially critical in asynchronous scenarios where data may become available only after some time.&lt;/p&gt;

&lt;p&gt;Additionally, components must be able to respond correctly to state changes. This means that the data source must notify recipients when information is updated, and the recipient must correctly recompute its state in response to such updates. Without this, interaction will either be reduced to a one-time data transfer or lead to desynchronization, where some components work with outdated data while others use new but unconfirmed information.&lt;/p&gt;

&lt;p&gt;That seems to cover everything. We have outlined all the requirements for linking two web components. These requirements can confidently be added to the &lt;a href="https://dev.to/valkoivo/initialization-of-a-web-component-with-external-data-2og3"&gt;criteria&lt;/a&gt; we previously defined for the environment necessary to initialize a component.&lt;/p&gt;

&lt;p&gt;Notice that none of these requirements mention that the recipient must know the data source's identifier. Moreover, there is no indication that the components must interact directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mediation in Component Communication
&lt;/h2&gt;

&lt;p&gt;Two web components can be linked not only directly but also through an intermediary. In this case, their interaction is facilitated by an additional element that takes on some of the responsibilities related to managing data transfer. But how does this approach differ from direct interaction between components?&lt;/p&gt;

&lt;p&gt;Examining this mechanism in detail reveals several key aspects. First, the intermediary assumes the data source’s responsibilities for handling requests from the recipient. This means that when the recipient requests information, it does not communicate with the original data source directly but rather with the intermediary, which either forwards the request or already possesses the necessary data.&lt;/p&gt;

&lt;p&gt;Second, the intermediary is responsible for transmitting notifications about data changes. When the data source updates its information, it can notify the intermediary, which, in turn, informs the recipient.&lt;/p&gt;

&lt;p&gt;However, the most important role of the intermediary is providing the recipient with information about the very existence and state of the data source. In a typical direct interaction scenario, the recipient must know where the source is and how to communicate with it. With an intermediary, this responsibility shifts: the intermediary monitors whether the source exists, what state it is in, and whether it is currently capable of providing data.&lt;/p&gt;

&lt;p&gt;Essentially, the intermediary takes on the data source’s functions related not to the data itself but to the communication process.&lt;/p&gt;

&lt;p&gt;From the recipient’s perspective, it does not matter which specific entity it interacts with. All that matters is that the entity has the required functionality for communication, meaning it conforms to a defined interface. If we replace the data source with an intermediary that provides the same interface, nothing changes from the recipient’s perspective. It continues sending requests and receiving data just as it would in direct interaction with the source. The only difference is that it now communicates with the intermediary instead of the original data source.&lt;/p&gt;

&lt;p&gt;This leads to an important observation: when an intermediary is present, it effectively becomes the recipient’s primary data source. Everything we have discussed—and will discuss—regarding the connection between a source and a recipient also applies to the source-intermediary-recipient model. To keep things simple, I will use the term source to refer to any entity the recipient communicates with, whether it is the original data source or an intermediary.&lt;/p&gt;

&lt;p&gt;At this point, you might wonder: “But does this entity even have to be a component?” The answer is no, not necessarily. While the main focus of this article is organizing communication between two web components, in a broader sense, we are discussing how a recipient obtains external data, regardless of its origin. Therefore, before moving forward, it makes sense to briefly discuss the nature of a data source.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Data Source?
&lt;/h2&gt;

&lt;p&gt;Broadening the definition of a data source, we can conclude that a source is not necessarily another web component—it can be something more abstract. It might be a signal reflecting a state change, a centralized data store, or even a global object accessible throughout the system. But how important is it to precisely define what qualifies as a data source?&lt;/p&gt;

&lt;p&gt;In reality, it’s not that critical. We have just established that our recipient component does not interact with a specific object but rather with an interface that provides the necessary functionality for communication. This means that any object conforming to the expected interface can automatically serve as a data source for the recipient.&lt;/p&gt;

&lt;p&gt;Moreover, just because your web component is currently linked to another component does not mean the situation will remain unchanged in the future. At some point, you might need to connect the recipient component not to another web component but, for example, to a reactive signal or a global state. Naturally, it would be preferable if this change did not require major code modifications. After all, one of our key goals is to ensure components are universal and flexible enough to be used in different contexts without excessive adjustments.&lt;/p&gt;

&lt;p&gt;Now, I’ll state something that may seem obvious but is no less important because of it. If the interfaces of the source and the recipient do not match—if one provides data in one format while the other expects it in another—an adapter will inevitably be required. An adapter aligns incompatible interfaces, ensuring proper interaction between different entities. We will explore adapters in more detail later, as it is an important topic.&lt;/p&gt;

&lt;p&gt;For now, let’s take a closer look at what an interaction interface between a data source and a recipient can actually be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handshake Methods
&lt;/h2&gt;

&lt;p&gt;Before two components can start interacting, they must first take the most important step—establishing initial contact. In the real world, communication between people begins when they introduce themselves to one another. In our case, this introduction can be understood as one entity notifying another of its existence. Without this step, no data exchange is possible, as the components simply wouldn’t know that they need to interact.&lt;/p&gt;

&lt;p&gt;To describe this crucial process, I will use the metaphor of a handshake. Just as a handshake in real life symbolizes the beginning of communication between people, in our system, it serves as the starting point for component interaction. It allows participants to confirm that they exist in the same environment and are ready to exchange data.&lt;/p&gt;

&lt;p&gt;But how exactly can this handshake be performed on a technical level? We have three main methods for establishing initial contact between components:&lt;/p&gt;

&lt;p&gt;Using events. One component can emit an event announcing its existence, while another component can listen for this event and thus become aware of the first. This method is particularly useful when components are not tightly coupled but interact within a dynamic system.&lt;/p&gt;

&lt;p&gt;Placing components in predictable locations within the DOM tree. If components are positioned in such a way that one can locate the other using DOM search methods (e.g., querySelector or closest), they can establish a connection simply by discovering each other in the document hierarchy. This approach works well when components are placed in expected locations and follow clear placement rules.&lt;/p&gt;

&lt;p&gt;Using an identifier. As mentioned in the previous article, one component can simply pass its unique identifier to another, allowing it to be found. This method is useful when connecting remote elements that are not in the same DOM context but still need to interact in some way.&lt;/p&gt;

&lt;p&gt;Each of these methods has its own characteristics, advantages, and limitations. To better understand their applications, let's examine them one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event-Based Handshake
&lt;/h2&gt;

&lt;p&gt;What makes an event-based handshake unique compared to other methods of establishing communication between components? Its key distinction is that an event does not have to be directed at a specific object. Instead, a receiving component can subscribe to a certain type of event and intercept all such events that bubble up from nested elements. This enables more flexible interactions since the data source does not need to be aware of a specific receiver’s existence, and the receiver, in turn, does not need to know the exact location of the source.&lt;/p&gt;

&lt;p&gt;At first glance, this method may seem to eliminate the need to pass an identifier for the data source into the component. And in a way, it does—the data source can generate events of a specific type, which the receiver can process without the source even knowing it exists. This approach allows data sources to be created dynamically without concern for how they will be linked to the receiver: the receiver will simply intercept the necessary events and take action accordingly. Moreover, this method abstracts away the identity of the data source itself. After all, the only requirement for the source is that it must be able to generate events of a certain type.&lt;/p&gt;

&lt;p&gt;However, there is an important nuance here that should not be overlooked. While using events removes the need to pass an identifier for a specific source object, it introduces a different kind of strict dependency: now, the receiver must know the identifier of the event type that the data source will emit. In essence, we have simply replaced one identifier with another—perhaps without even realizing it.&lt;/p&gt;

&lt;p&gt;For this interaction to work, both the source and the receiver must agree in advance on which specific events will be used for communication. But where and how should this agreement be established? The most straightforward approach is to document it. In practice, this is exactly what is usually done: a component’s documentation specifies which events it emits and which events it can handle.&lt;/p&gt;

&lt;p&gt;But is this approach truly universal and flexible? Not entirely. Imagine that we need to change the receiver’s behavior so that it responds to a different event instead of the current one. If the event type is hardcoded, we would have to manually locate and replace it in the code. However, we have already discussed that hardcoded identifiers are not a best practice, as they make components harder to maintain and reuse.&lt;/p&gt;

&lt;p&gt;Thus, events serve as a technical mechanism for transmitting information, but they do not solve the handshake problem itself. If a receiving component is to remain independent of the source, it must still be informed in advance—either of the source’s identifier or of the event type the source will use.&lt;/p&gt;

&lt;p&gt;That said, there is another way to establish a connection between components that does not require passing identifiers. Let’s explore that next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Addressing
&lt;/h2&gt;

&lt;p&gt;As we have just established, it is possible to link two components without explicitly passing the data source’s identifier. However, despite this, the receiver still requires some information about the source; otherwise, it will be unable to establish a connection. Now, let’s explore whether a handshake can be performed not through the transfer of an identifier but by knowing the source’s location within the DOM tree.&lt;/p&gt;

&lt;p&gt;Imagine you need to receive a package. If you know the sender’s identifier (such as their phone number), you can simply call them and arrange the delivery. This is equivalent to a scenario where the receiving component knows the data source’s identifier and communicates with it directly.&lt;/p&gt;

&lt;p&gt;But there is another option. Instead of contacting the sender by phone, you can pick up the package yourself if you know the pickup location. In this case, the sender’s identifier is not needed—just the location where the package can be found. And if you have access to a directory, knowing the address might even allow you to determine the sender’s phone number, ultimately reducing the task to the previous scenario.&lt;/p&gt;

&lt;p&gt;A similar logic can be applied to web components. If the receiver knows where to look for the source in the DOM, it can establish a connection without needing to know its identifier.&lt;/p&gt;

&lt;p&gt;Of course, requiring the data source to always be in a strictly defined place within the DOM is impractical and often impossible. There are several reasons why such a rigid binding does not work:&lt;/p&gt;

&lt;p&gt;Flexibility of the DOM structure. The structure of a web page is dynamic and is not always controlled by the developer of a specific component. Components can be added or removed depending on business logic, application state, or user actions.&lt;/p&gt;

&lt;p&gt;Separation of responsibilities. One developer may be responsible for creating a web component, while another integrates it into the interface. A strict dependency on a specific location in the DOM would introduce additional challenges when using the component in different projects.&lt;/p&gt;

&lt;p&gt;Instead of rigid positioning, relative placement of components can be used. The most common approach to organizing such interactions is by leveraging a parent-child hierarchy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiver Inside the Source
&lt;/h2&gt;

&lt;p&gt;The parent-child relationship is a widely used concept in organizing interactions between built-in components. This relationship can be observed in various places: for example, when structuring a list, where li elements are placed inside their parent ul, or when constructing a table, where tr rows and td cells follow a strict nested structure defined by HTML rules. Additionally, this model is commonly applied in other components that require a well-organized hierarchy for proper functioning.&lt;/p&gt;

&lt;p&gt;This naturally raises the question: how effective is this model for organizing interactions between web components?&lt;/p&gt;

&lt;p&gt;Let’s assume the receiver is located inside the source. In this case, the receiver can access its parent element using the parent property. This approach is intuitive for most developers since it has long been used in web development and does not introduce additional complexity. From the perspective of conceptual clarity and simplicity, this method aligns with the principles we previously discussed in earlier articles. However, one question remains: how well does this approach meet other important criteria?&lt;/p&gt;

&lt;p&gt;Enforcing a strict nesting requirement means that two components become linked not only logically but also structurally. This implies that the developer must adhere to this rule when building the DOM tree and ensure that the document structure remains valid. Moreover, such a rigid constraint can significantly reduce an application’s architectural flexibility and make it more challenging to implement certain scenarios.&lt;/p&gt;

&lt;p&gt;Let’s examine a practical example. Suppose we have a single data source and two receivers that need to obtain data from it. If we strictly follow the parent-child model, both receivers must be positioned close to the source—that is, at the same level of nesting within the parent. However, in real-world applications, the same data often needs to be displayed in different parts of the interface, and the corresponding components may be located far apart. In such cases, the nesting rule becomes a serious limitation.&lt;/p&gt;

&lt;p&gt;One way to overcome this limitation is through event-based communication. Suppose our data receiver is not inside the source but is instead several levels deeper in the document structure. In this case, the receiver can send an event that bubbles up the DOM tree, notifying the data source of its presence. This can be achieved using the bubbles property of the event object, which allows information to propagate through the hierarchy of parent elements.&lt;/p&gt;

&lt;p&gt;However, even with this approach, some challenges remain. While the components are now less tightly coupled, a dependency still exists. The developer still cannot freely reposition either the source or the receiver without considering their relative placement. This means that whenever the DOM structure changes—whether due to product evolution or feature expansion—the entire document organization may need to be revisited. In some cases, this modification might require additional specialists, such as front-end developers working on layout and design.&lt;/p&gt;

&lt;p&gt;Even this does not exhaust all potential complexities. Let’s consider another scenario involving dynamic data sources. Imagine we have two different data sources and a single receiver. For example, suppose we have a chart component that visualizes incoming data. This chart should be able to receive data from either a remote server or a local file uploaded by the user. Ideally, the user should have the ability to select the data source dynamically.&lt;/p&gt;

&lt;p&gt;One possible implementation involves creating two separate source components: one for retrieving data from a server and another for loading data from a file. In an ideal system, the chart should be able to switch between these sources in real-time. However, if our architecture enforces a strict parent-child model, we would have to nest the data receiver inside one source and then somehow re-nest it into another source when switching.&lt;/p&gt;

&lt;p&gt;The situation becomes even more complex if data sources need to be added dynamically. For instance, as the product evolves, new types of sources may need to be supported. In such cases, developers face the challenge of restructuring the entire component hierarchy to accommodate these changes.&lt;/p&gt;

&lt;p&gt;Despite its simplicity and intuitive nature, the parent-child model imposes significant limitations when used with web components. In many cases, this model lacks the flexibility needed to handle dynamic component interactions effectively. While it can be useful for certain well-structured relationships, it is not always the best choice for systems that require dynamic or loosely coupled communication between components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Inside the Receiver
&lt;/h2&gt;

&lt;p&gt;Now, let's consider a situation opposite to the one we discussed earlier. Imagine that the data source is located inside the receiver.&lt;/p&gt;

&lt;p&gt;First of all, based on our previous observations, we can immediately point out an example that highlights the drawbacks of this approach. Let’s examine a case where we have two data receivers and only one source. Obviously, if the data source is embedded within one of the receivers, the second receiver loses access to it. This, in itself, is already a strong argument against this approach, as it introduces unnecessary restrictions.&lt;/p&gt;

&lt;p&gt;However, a logical question arises: if this setup has such obvious disadvantages, why is event bubbling used in web development? After all, the bubbling mechanism specifically addresses the problem of passing information from nested elements to their parents.&lt;/p&gt;

&lt;p&gt;The answer lies in the fact that technological solutions are not always designed to completely eliminate a problem in all its possible forms. Sometimes, their primary goal is simply to make solving the most common specific cases easier. Web technologies often evolve in a way that provides developers with convenient tools for handling typical tasks while leaving more complex and rare scenarios unresolved, requiring additional effort.&lt;/p&gt;

&lt;p&gt;Let’s analyze situations where nesting sources and receivers within each other actually complicates system architecture. The main difficulty arises when a single data source needs to serve multiple receivers, or conversely, when a single receiver needs to interact with multiple sources.&lt;/p&gt;

&lt;p&gt;But what if we know in advance that a data source will never be used anywhere except within a strictly defined receiver? Would nesting the source inside the receiver create any problems in that case?&lt;/p&gt;

&lt;p&gt;Consider a concrete example. Suppose we have a button that triggers some action—such as a button within a dialog window. In this case, the button acts as the information source, while the dialog window serves as the receiver. The button transmits data containing a command to the window, and the window itself decides what to do with this data. Meanwhile, all other components in the system don’t need to be aware of the button’s existence since they don’t interact with it in any way.&lt;/p&gt;

&lt;p&gt;In this situation, the proposed approach turns out to be not only applicable but even beneficial. Placing the source inside the receiver reduces component coupling because the window does not need to be aware of the specific buttons inside it. This, in turn, increases system flexibility, allowing for dynamic creation and modification of button sets without requiring changes to the window's logic.&lt;/p&gt;

&lt;p&gt;However, even in this scenario, there is one nuance that cannot be overlooked. How exactly will the button transmit information to the dialog window? An obvious solution is to use events, but in doing so, the button and the window must agree on the type of event being transmitted. This means that while coupling is reduced in one aspect, dependency still remains in another: the button needs to know what event to generate, and the window needs to know what event to listen for and how to handle it.&lt;/p&gt;

&lt;p&gt;Thus, even when using source nesting within the receiver to improve usability for a specific component, there remains a need for an agreement between them regarding the interaction format. This brings us back to the necessity of passing an event type identifier to the button.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Bad Is It to Use an Identifier?
&lt;/h2&gt;

&lt;p&gt;Summing up everything discussed above, we can draw an important conclusion: if there is a relatively simple and efficient way to organize interaction between two web components without tightly coupling them to their position in the DOM structure, it makes sense to use it.&lt;/p&gt;

&lt;p&gt;However, another equally important conclusion follows from everything stated earlier: no matter how much we try, we cannot completely avoid the need to pass some kind of identifier that allows the source and the receiver to "recognize" each other and establish a connection. Therefore, we should examine what compromises and potential downsides come with using identifiers for communication between web components.&lt;/p&gt;

&lt;p&gt;At first glance, using an identifier may not seem like the most obvious or intuitive way to establish interactions between elements. Moreover, observing the various alternative approaches that developers often try to come up with for solving similar tasks, I have concluded that using an identifier is not only unintuitive for many but also poses certain difficulties for a significant portion of developers. This may be because many are accustomed to thinking in terms of the hierarchical DOM structure and consider element nesting to be the natural and only correct way to organize interactions.&lt;/p&gt;

&lt;p&gt;To determine whether an identifier is indeed an unintuitive way to establish connections, let's look at examples of existing built-in HTML elements that use this mechanism.&lt;/p&gt;

&lt;p&gt;As is well known, the label element can be linked to an input field using the for attribute. This attribute must contain the id of the corresponding input, allowing the user to click on the label and automatically focus on the associated input field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, the output element, which is used to display computed values, can be linked to one or more input elements via the for attribute. This makes it clearer which input fields influence the computed result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;oninput=&lt;/span&gt;&lt;span class="s"&gt;"result.value=parseInt(a.value)+parseInt(b.value)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; +
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; =
  &lt;span class="nt"&gt;&amp;lt;output&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"a b"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/output&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The datalist element provides users with a list of predefined options associated with a specific input. The connection between them is established through the list attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;list=&lt;/span&gt;&lt;span class="s"&gt;"browsers"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;datalist&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"browsers"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Chrome"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Firefox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/datalist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This list could go on for quite a while, as the mechanism of explicitly specifying relationships between elements using identifiers is widely used even in standard HTML components. Thus, we can conclude that this approach is neither unusual nor rare—on the contrary, it has long been a well-established, convenient, and flexible way of linking elements in web development.&lt;/p&gt;

&lt;p&gt;But here arises a logical question: if this approach is indeed so convenient and widespread, why do many developers intuitively prefer nesting and event bubbling for establishing connections?&lt;/p&gt;

&lt;p&gt;Therefore, before drawing final conclusions, we need to verify whether using an identifier truly simplifies component behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obtaining a Reference to the Data Source
&lt;/h2&gt;

&lt;p&gt;When we talk about a data source identifier that is passed to the receiver, it is important to remember that an identifier is merely a string used to designate an element—it does not provide direct access to it. In other words, having an identifier does not mean we can call the source’s methods or interact with it directly. To do that, we need a reference to the actual object we want to work with.&lt;/p&gt;

&lt;p&gt;This raises the question: how can we obtain this reference if all we have is an identifier? Fortunately, standard web development tools offer a well-known and widely used way to find elements in the DOM. For instance, we can use methods like document.getElementById(), document.querySelector(), or document.querySelectorAll() to locate an element by its identifier. This is a common practice when working with various elements on a page.&lt;/p&gt;

&lt;p&gt;However, as with any approach, there are potential situations where this method may not work.&lt;/p&gt;

&lt;p&gt;With declarative initialization, there are no issues. Even if the source itself has not yet been fully initialized, as long as its tag is present in the DOM tree, the receiver can easily obtain a reference to it using document.getElementById().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-source&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"data-source"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-component&lt;/span&gt; &lt;span class="na"&gt;source_id=&lt;/span&gt;&lt;span class="s"&gt;"data-source"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;source_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of dynamic initialization, the situation can be different. If the receiver is inserted into the DOM before the source, it will not be able to immediately obtain a reference to the source using document.getElementById(), since the source simply does not exist yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;source_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we are working with dynamically created elements, we have another approach available. When creating the source, we can store a reference to it and pass this reference directly to the receiver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;source_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, working with data source identifiers is a straightforward and intuitive process. In most cases, if the data source is created declaratively, no issues arise at all. With dynamic initialization, the order in which elements are inserted into the DOM must be taken into account, but this is not a significant challenge. Thus, we can confidently say that, at least for establishing an initial connection ("handshake") between two web components using an identifier, a simple and predictable approach is sufficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Death of a Reference
&lt;/h2&gt;

&lt;p&gt;When discussing mechanisms for working with identifiers, there is another crucial aspect that developers often overlook when designing web components and interaction systems between elements: proper reference management when objects are removed.&lt;/p&gt;

&lt;p&gt;At first glance, this might not seem like a significant issue—after all, browsers have a garbage collector that automatically frees memory occupied by unused objects. However, for this mechanism to function correctly, developers must follow certain rules. Ignoring these rules can lead to memory leaks, unexpected component behavior, and difficult-to-debug errors.&lt;/p&gt;

&lt;p&gt;If a receiver holds a reference to a data source, and one of them is later removed, different scenarios can arise depending on how references are handled and the type of object being deleted.&lt;/p&gt;

&lt;p&gt;If the receiver is removed while the source continues to exist, memory leaks typically do not occur. The receiver disappears, and its references to the source are no longer used, allowing the garbage collector to free up memory. However, if the source maintained a reference back to the receiver (e.g., via a subscription or callback), the memory may not be freed until this connection is explicitly broken.&lt;/p&gt;

&lt;p&gt;If the source is removed while the receiver still holds a reference to it, the source object will not be garbage collected, even if it is no longer used elsewhere in the program. This can lead to memory leaks, especially if the source consumes significant resources.&lt;/p&gt;

&lt;p&gt;To prevent such issues, developers can use weak references (WeakRef) or unsubscribe mechanisms (e.g., explicitly removing event listeners). A good practice is also to break all unnecessary references in disconnectedCallback.&lt;/p&gt;

&lt;p&gt;This raises an important question: if we establish connections between components using references, who should be responsible for managing them? Should the developer using the web component handle this manually? Clearly, it’s better to eliminate that burden. The correct approach is for the component itself to manage references properly, ensuring that it can be used without requiring the developer to worry about these details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Let’s summarize the key takeaways from our discussion.&lt;/p&gt;

&lt;p&gt;Regardless of the chosen approach for establishing a "handshake" between web components, the use of an identifier is unavoidable. This identifier plays a critical role, as it enables retrieving a reference to the data source or initiating an event-based communication mechanism.&lt;/p&gt;

&lt;p&gt;An adapter will likely be necessary when transferring data between components. This is especially relevant when the source and receiver expect data in different formats or operate based on different principles.&lt;/p&gt;

&lt;p&gt;It must be possible to change the identifier dynamically. In real-world applications, the data source may change, meaning the receiver must be able to adapt without losing functionality.&lt;/p&gt;

&lt;p&gt;Web components may be removed from the DOM during operation. The system must be designed to handle cases where either the source or the receiver ceases to exist. Failing to account for this can lead to memory leaks or lingering references to nonexistent elements.&lt;/p&gt;

&lt;p&gt;This behavior is not tied to any specific source or receiver implementation. It can be generalized and applied to various web components, making it worth formalizing into a reusable solution.&lt;/p&gt;

&lt;p&gt;In the next article, we will begin exploring how to implement such behavior.&lt;/p&gt;

&lt;p&gt;Looking ahead, this is precisely the behavior I have implemented in the KoiCom library. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;KoiCom documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;KoiCom github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use this solution in your projects to simplify web component interactions and avoid numerous potential pitfalls.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Methods for Initializing Web Components with External Data</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Sun, 02 Feb 2025 10:30:16 +0000</pubDate>
      <link>https://dev.to/valkoivo/methods-for-initializing-web-components-with-external-data-4de1</link>
      <guid>https://dev.to/valkoivo/methods-for-initializing-web-components-with-external-data-4de1</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/valkoivo/initialization-of-a-web-component-with-external-data-2og3"&gt;previous article&lt;/a&gt;, we discussed the criteria that the environment initializing a web component should meet. Now, we face the next question: which method of initializing a web component should be chosen if external data needs to be passed to it?&lt;/p&gt;

&lt;p&gt;In this article, we will explore the main methods for initializing a web component, discussing their advantages and disadvantages using the criteria from the previous article. I promise it will be more tedious than usual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Methods of Passing Data During Initialization
&lt;/h2&gt;

&lt;p&gt;There are many different ways to initialize a web component, each with its own features and nuances. Classifying these methods strictly and unambiguously is quite difficult, as in practice, they rarely appear in their pure form. More often, developers combine various approaches, selecting the most convenient or efficient solutions for a specific task. However, to have a starting point in this variety, let’s begin by distinguishing based on a key factor: whether the server is involved in the process of initializing the web components.&lt;/p&gt;

&lt;p&gt;If the server is involved, it not only chooses the specific components and data with which they will work, but also controls their codebase. In this case, one can say that the server generates the final component code. To do this, it may use various tools, such as templating engines, transpilers, optimizers, and minifiers. As a result, the browser ends up with pre-processed code that has gone through all the necessary preparation stages. In essence, this code is similar to a compiled program, and therefore, the programmer working in the browser typically does not need to understand the details of its structure.&lt;/p&gt;

&lt;p&gt;It is important to mention that debugging such code in the browser can sometimes be a real challenge. Developers working with server-oriented frameworks often struggle to figure out what is actually happening in the code they receive after all these transformations. In such cases, analyzing the code often leads to confusion and requires a lot of brainpower.&lt;/p&gt;

&lt;p&gt;But let's return to the features of the server-side approach. Since the server has full control over the code, it is not obligated to produce code with the characteristics of good code. In other words, the server does not need to follow the component initialization rules that programmers adhere to for readability and usability. Compiled code is subject to entirely different requirements, focused on rendering efficiency and resource optimization.&lt;/p&gt;

&lt;p&gt;When it comes to passing data in such an approach, any methods, even the most rudimentary ones, can be applied. Here is a simple example illustrating how data can be hardcoded for a web component directly on the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$hardcodedTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?=&lt;/span&gt;&lt;span class="nv"&gt;$hardcodedTitle&lt;/span&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;my-component&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the server pre-inserts data into the component before sending the HTML code to the browser. This approach, of course, goes against the principles of good code, but it is fully functional. In this case, the browser does not need to reuse or extend the component or interact with it in any way other than displaying it on the page. It simply receives the ready-made instance and uses it as is.&lt;/p&gt;

&lt;p&gt;From this, we can conclude that with server-side initialization, web components are not strictly necessary. The server can form the interface using standard HTML elements or any other available tools. In this context, web components are no more than an additional layer of abstraction, which doesn’t always make sense.&lt;/p&gt;

&lt;p&gt;But when we talk about web components, we are not just interested in their existence but in the ability to operate with them as independent, autonomous units that are understandable not only to the browser but also to the developer. That’s why server-side initialization methods are beyond the scope of our discussion. Instead, we will focus on those methods that allow web components to be initialized directly in the browser.&lt;/p&gt;

&lt;p&gt;This means that in our case, the application will run in the client environment, initializing components in the DOM at runtime. In this article, we will cover two such methods. The first method involves creating a component and then placing it in the DOM using JavaScript code — we will refer to this as dynamic initialization. The second method involves pre-defining the HTML tag for the component in the markup — we can call this declarative initialization. Both approaches have their pros and cons, and we will examine their features in detail later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Initialization
&lt;/h2&gt;

&lt;p&gt;Dynamic initialization of a web component is carried out as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;my_component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some_property&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, you can see that setting values for a web component’s properties occurs after the constructor is called and before the component is added to the DOM. This order is due to the fact that the constructor is intended solely for basic initialization, meaning that attributes, internal elements of the component, or even parameters for the constructor should not be accessed within it. Although the web component specification does not prohibit the explicit use of parameters in the constructor, practice shows that this approach is not recommended. Data should be passed to the component only after the constructor has finished.&lt;/p&gt;

&lt;p&gt;In all other respects, working with a web component is similar to interacting with ordinary JavaScript classes. For the component, you can define getters and setters, methods for data handling, and other state management mechanisms. As &lt;a href="https://dev.to/valkoivo/data-models-and-web-components-1jpa"&gt;mentioned earlier&lt;/a&gt;, it is useful for a web component to have an object for its own data. If you follow this principle, the following approach can be implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyDataCapable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;onConstructed&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setInitialValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;getDataValue&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;MyDataCapable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConstructed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDataValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;my_component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInitialValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;my_component&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extracting methods that pass data to the data object can be implemented as a behavior, which is just as convenient as using interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declarative Initialization
&lt;/h2&gt;

&lt;p&gt;Declarative initialization of a web component is a method of creating and configuring a component using familiar HTML markup. In this approach, data is passed through attributes, nested elements, or other mechanisms that allow for expressive and structured descriptions of the component's state and content directly in the markup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt; &lt;span class="na"&gt;data-value=&lt;/span&gt;&lt;span class="s"&gt;"42"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we set the component's title using the title attribute and pass a numerical value into the component via data-value. However, declarative initialization is not limited to just attributes. Data can also be passed using nested elements, which makes the structure more flexible and readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;John&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;30&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is particularly useful when working with complex data structures, as it clearly defines the nesting of elements and their relationships.&lt;/p&gt;

&lt;p&gt;One of the key advantages of declarative initialization is the improvement of code readability and clarity. The markup reflects the final interface structure, making it easier to understand for both developers and designers or content editors. Unlike imperative programming, where the order of commands determines the result only at runtime, the declarative approach makes the interface structure apparent from the very beginning. This reduces the likelihood of errors, speeds up development, and simplifies project maintenance, as even without deep code knowledge, one can quickly understand which elements are present and how they are organized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disadvantages of Declarative Initialization
&lt;/h2&gt;

&lt;p&gt;While the declarative approach is widely recognized and intuitively understandable, it is not without its drawbacks, one of which becomes evident when passing data into a component. The issue is that, in declarative initialization, the component is declared in the HTML markup through its tag, and HTML, being a text-based format, operates with string values. This means that any data passed into a component via attributes must be converted to a string type, even if the data originally consists of numbers, boolean values, arrays, objects, or functions.&lt;/p&gt;

&lt;p&gt;This limitation significantly impacts the flexibility of working with web components, and many developers seek ways to bypass it. However, there is no universal solution. Whatever workaround you choose, it will require the programmer using your component to take extra steps and lead to the need to write auxiliary code.&lt;/p&gt;

&lt;p&gt;Moreover, the workaround itself may not be obvious or intuitive. It imposes on the programmer the necessity to follow a certain sequence of steps, which is not always standard or intuitive. As a result, in order to use the component, one must study the component's source code to understand how it processes the passed data and manually add code each time to convert the data into the required format.&lt;/p&gt;

&lt;p&gt;To simplify this process and make it as convenient as possible, it is best to provide support for the necessary conversions within the component itself. This can be implemented either as built-in behavior or as part of the API. In this case, the developer won't need to worry about how to pass complex data — the component will take care of properly handling the input values.&lt;/p&gt;

&lt;p&gt;However, before deciding to tackle this issue, it is important to understand whether it is worth solving at all. Let's first explore why the declarative approach is needed and what advantages it offers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Declarative Initialization is Used
&lt;/h2&gt;

&lt;p&gt;There are numerous advantages to working with dynamic initialization. Dynamic initialization of a web component provides great flexibility. We don't just tell the component to accept data, but instead, we engage in a dialogue with it, during which we can ask the component to validate data before inserting it into the DOM and synchronize data fragments with each other.&lt;/p&gt;

&lt;p&gt;However, perhaps the main advantage of dynamic initialization is that it removes the limitation related to passing data through attributes. Since JavaScript can work with any data types, a component can be passed not only strings but also objects, arrays, and functions, making interaction with it much more powerful and convenient.&lt;/p&gt;

&lt;p&gt;However, the dynamic approach also has a downside: it requires explicit programming, meaning that every time, code must be written to call and configure the component. This increases the amount of code, complicates readability, and makes working with the component less intuitive.&lt;/p&gt;

&lt;p&gt;This is the main reason why declarative initialization remains a more convenient and natural way to work. Using HTML notation allows you to immediately see the final structure of the components on the page, and the process itself stays simple and clear.&lt;/p&gt;

&lt;p&gt;The second important advantage of the declarative approach is the encapsulation of logic within the component. Since all attributes are defined in the HTML markup, the developer doesn't need to worry about the order in which the component processes them — it will handle the passed values and perform the necessary actions. This simplifies the workflow and helps avoid potential errors related to method call order or data processing.&lt;/p&gt;

&lt;p&gt;Finally, the declarative approach promotes task delegation within a team. One developer can focus on creating and configuring components in the markup based on documentation, while another can work on the component itself, not worrying about how it will be used in the final code. This makes the development process more organized and predictable.&lt;/p&gt;

&lt;p&gt;And only one significant limitation prevents declarative initialization from becoming a universal solution. This is the inability to pass any values other than strings in HTML attributes. This means that complex data structures, such as objects or arrays, cannot be passed directly through attributes, which forces developers to look for workarounds.&lt;/p&gt;

&lt;p&gt;But let's dig even deeper into this issue. Let's assume that we create a convenient and simple mechanism for passing complex data structures. If we learn how to pass complex values in declarative form, will it simplify the process of initializing components? I’ve mentioned this earlier. Our main goal is to simplify the implementation of the environment needed for component initialization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing Data in JSON
&lt;/h2&gt;

&lt;p&gt;The simplest and most obvious way to pass complex data, such as arrays or objects, into a web component is to convert them into a JSON string. This is a standard method of data serialization, supported by all modern browsers and widely used in web development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;banana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data_array&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;my-component data-items="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;json_data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&amp;lt;/my-component&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html_string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I see this kind of code almost all the time. However, it’s not immediately clear to everyone that when converting to JSON, we get a set of different quotation marks in the resulting string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; JSON.stringify('"');
&amp;lt; '"\\""'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, a simple conversion to JSON could potentially cause an error or pass the wrong value into the component. Therefore, it is advisable to also use encodeURIComponent.&lt;/p&gt;

&lt;p&gt;But this is not the most important part. What matters is that now any data structure can be serialized, encoded, and passed into the web component, and the component itself can include logic to decode and process that data. This means that the environment in which the components are placed no longer needs to worry about how to prepare the data for each specific component. Instead, we have a unified encoding method that can be applied to all components in the project, and the developer only needs to remember one rule: always pass data through a special method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;encodeJsonArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;banana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encodeJsonArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data_array&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;my-component data-items="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;json_data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&amp;lt;/my-component&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html_string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clearly, this significantly simplifies the process of preparing the environment for working with components. However, this approach has its drawbacks.&lt;/p&gt;

&lt;p&gt;Imagine that we don't have access to JavaScript in the environment where we are forming the HTML markup. In that case, we won't be able to call our "magic" function, and we'll have to manually encode the data, knowing which characters need to be escaped. Can we quickly encode a string without errors? Experienced developers may be able to do this, but for most people, this process will be challenging.&lt;/p&gt;

&lt;p&gt;An even bigger issue arises in the opposite situation: if we need to quickly understand what data has been passed in an encoded form, it's nearly impossible to do this without decoding it. encodeURIComponent turns regular characters into %XX sequences, making the string hard to read. It's quite difficult to immediately determine what exactly is hidden behind the resulting "gibberish." This reduces code readability, and as we’ve noted before, readability is one of the key reasons we use the declarative approach.&lt;/p&gt;

&lt;p&gt;Thus, we find ourselves facing a dilemma: on one hand, we have a universal mechanism for passing data, but on the other hand, we’ve reduced the transparency of the code. The question is whether we can find a compromise solution that retains the convenience of the declarative approach while still allowing us to pass complex data structures. Are there ways to make this process more convenient and intuitive?&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Multiple Attributes
&lt;/h2&gt;

&lt;p&gt;Passing data to a web component using multiple individual attributes in a declarative initialization has several significant advantages. First and foremost, this approach makes the HTML markup more understandable and self-documenting. Each attribute clearly indicates its role, making it immediately obvious what parameters are being passed to the component and what they are responsible for.&lt;/p&gt;

&lt;p&gt;Additionally, separating values via attributes can have a positive impact on performance. The browser does not need to parse complex JSON objects, which speeds up page processing. An added benefit is that individual attributes can be cached by the browser, while passing data in a single large JSON object may result in the entire object being recreated when even one parameter is changed, which is less efficient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&lt;/span&gt; 
  &lt;span class="na"&gt;user-name=&lt;/span&gt;&lt;span class="s"&gt;"John Doe"&lt;/span&gt; 
  &lt;span class="na"&gt;user-age=&lt;/span&gt;&lt;span class="s"&gt;"30"&lt;/span&gt; 
  &lt;span class="na"&gt;user-location=&lt;/span&gt;&lt;span class="s"&gt;"New York"&lt;/span&gt; 
  &lt;span class="na"&gt;user-role=&lt;/span&gt;&lt;span class="s"&gt;"Admin"&lt;/span&gt; 
  &lt;span class="na"&gt;user-status=&lt;/span&gt;&lt;span class="s"&gt;"Active"&lt;/span&gt; 
  &lt;span class="na"&gt;user-signup-date=&lt;/span&gt;&lt;span class="s"&gt;"2025-01-01"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, each attribute clearly defines its purpose, and even without documentation, it is clear what parameters are being passed to the component.&lt;/p&gt;

&lt;p&gt;However, this method also has its downsides. The first drawback is the need to remember the names of all available attributes and their allowed values. With JSON or objects in JavaScript, you can work with logically grouped data, while with attributes, the developer is forced to define each parameter individually. This increases the likelihood of errors and typos, especially if there are many attributes and their list may change over time.&lt;/p&gt;

&lt;p&gt;The second disadvantage is that some parameters may have dependencies. For example, if a component supports both dark and light modes, as well as color customization, situations may arise where one attribute affects another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt; &lt;span class="na"&gt;theme-color=&lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, how the component interprets the passed data is important: will it automatically adjust theme-color based on the mode, or does the developer need to account for incompatible combinations? As the number of attributes increases, managing such dependencies becomes more complex, and the likelihood of errors increases.&lt;/p&gt;

&lt;p&gt;Another issue is that attributes do not support nested structures. If you need to pass complex data, such as an array or an object with nested properties, workarounds must be found. One option is to use additional prefixes to distinguish related data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&lt;/span&gt; 
  &lt;span class="na"&gt;item-1-title=&lt;/span&gt;&lt;span class="s"&gt;"Item One"&lt;/span&gt; 
  &lt;span class="na"&gt;item-1-price=&lt;/span&gt;&lt;span class="s"&gt;"10.99"&lt;/span&gt; 
  &lt;span class="na"&gt;item-2-title=&lt;/span&gt;&lt;span class="s"&gt;"Item Two"&lt;/span&gt; 
  &lt;span class="na"&gt;item-2-price=&lt;/span&gt;&lt;span class="s"&gt;"15.49"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus, using multiple attributes in declarative initialization is great for simple cases where the number of parameters is small and they do not depend on each other. However, as the data structure becomes more complex, this approach starts to suffer from redundancy, reduced readability, and more complicated code maintenance. In such cases, it may be worth considering alternative solutions that maintain the convenience of the declarative approach but allow for handling complex data structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Nested Tags
&lt;/h2&gt;

&lt;p&gt;To simplify the representation of complex data structures in a readable and intuitive format, nested tags can be used. This approach allows related elements to be logically grouped within a parent component, making the code easier to comprehend. The nesting in HTML markup naturally reflects the hierarchy of the data, making the structure visual and predictable. This is especially useful when passing lists, tree structures, or complex configurations, as each level of nesting clearly indicates the relationships between elements. As a result, the likelihood of errors is reduced, editing code is simplified, and the process of reading the markup becomes more natural and understandable, even for those unfamiliar with the internal workings of the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;John Doe&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;30&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"location"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;New York&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"role"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Admin&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Active&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"signup"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2025-01-01&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;data-item&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"method"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/data-item&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the drawbacks. The developer needs to remember the rules for the structure of the markup: which elements can be nested inside the component, in what order they should appear, and which of them are mandatory. Unlike passing data via attributes, where the list of parameters is usually fixed and described in the API, here the developer requires additional understanding of the allowed nesting hierarchy. If the component documentation is not detailed enough, the developer will need to figure this out manually, which could take a lot of time.&lt;/p&gt;

&lt;p&gt;Another disadvantage is that working with nested elements requires additional parsing on the component’s side. The component needs to process its child elements, analyze their contents, and build its internal logic based on them. This increases the overhead compared to simpler methods of passing data, such as passing a JSON string through an attribute. This becomes particularly noticeable when dealing with large volumes of data, as the number of nested nodes significantly increases.&lt;/p&gt;

&lt;p&gt;Finally, nested tags can make code maintenance more difficult in large projects. If the markup structure is complex and multi-layered, making changes to one component may require adjusting other dependent components. For example, if the format of the data expected by the component changes, the entire data-passing structure must be reconsidered, which requires more effort.&lt;/p&gt;

&lt;p&gt;Thus, using nested tags to pass data to a component has both pros and cons. On the one hand, this method makes the code visual, intuitive, and suitable for working with tree-like structures. On the other hand, it requires additional control over the data structure, increases computational load, and complicates long-term maintenance. Therefore, when choosing this approach, one should consider the complexity of the data, the frequency of changes, and the requirements for ease of working with the markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison of Declarative Approaches
&lt;/h2&gt;

&lt;p&gt;The methods of passing data to web components described above undoubtedly open up the possibility of working with complex data structures, which helps eliminate the main limitation of the declarative approach — the restriction on passing non-string values. Now we can pass arrays, objects, nested structures, and thus, the flexibility and expressiveness of declarative initialization significantly increase. However, as is often the case, solving one problem inevitably leads to the emergence of another.&lt;/p&gt;

&lt;p&gt;The new drawback is that, by using all these methods of data transfer, we are not simplifying the process of setting up the environment but instead creating additional complexities. Now, the programmer must not only pass data in its natural form but also transform it beforehand, following certain rules that depend on the method of transmission. As a result, preparing the environment no longer appears intuitive and obvious. On the contrary, it becomes a process that requires knowledge of numerous nuances, careful adherence to specific conventions, and constant vigilance to ensure nothing is forgotten or mixed up.&lt;/p&gt;

&lt;p&gt;A dilemma arises. On the one hand, we want to work with complex data structures, as this makes the components more powerful and easier to use. On the other hand, we would like the data transfer process itself to be as simple as possible and not require the developer to remember a myriad of specific rules and transformations. After all, the more such rules there are, the higher the chance of making an error, the more difficult the code becomes to maintain, and the longer it takes to write.&lt;/p&gt;

&lt;p&gt;This problem can be formulated in an even broader context. The main difficulty we face is that the process of generating a component tag requires us to remember too many details.&lt;/p&gt;

&lt;p&gt;Nevertheless, I would like to propose two ways of solving this problem, which may prove useful in two specific scenarios. They are not universal, but perhaps they will provide a direction for further thought and help minimize the very complexities we are currently discussing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Generation of Tags
&lt;/h2&gt;

&lt;p&gt;Let’s imagine a situation where we need to generate an HTML tag for a web component and then insert it into the desired place in the document. In this process, we encounter several potential issues. First, there is doubt about whether we have specified the attribute values correctly, which are necessary for the proper initialization of the component. We are not sure if the structure of the nested tags meets all the requirements and properly reflects the component's logic. Additionally, there is a chance that we may have incorrectly applied methods to transform the data, which could lead to errors in the component’s functionality. In such a situation, we don’t want to constantly remember all these complex rules, and we don’t want to waste time performing endless checks to make sure everything is done correctly. However, as often happens when a programmer faces a task they don’t want to solve manually, they turn to programming to automate the process.&lt;/p&gt;

&lt;p&gt;Why not create a method that would allow us to automatically generate the HTML tag for the component while also verifying all the aspects we might have doubts about? This would relieve us from the need to manually track every detail and significantly simplify the process of working with the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getTag&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cannot be below zero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;my-component value="&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the MyComponent class has a static method getTag, which creates the component's tag and ensures that the data passed to the component follows certain rules.&lt;/p&gt;

&lt;p&gt;Now, when we generate the necessary HTML code, it can easily be inserted into the document while maintaining the readability of the HTML markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;holder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;h1&amp;gt;Some Title&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The value is &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTag&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach solves our task and significantly simplifies the code. We no longer have to manually build a string with the component's tag, constantly checking the correctness of values and structure. Instead, we can use the getTag method, which performs all the necessary checks and returns us the ready tag string. This method of organizing the code not only speeds up development but also reduces the likelihood of errors related to incorrect data formation.&lt;/p&gt;

&lt;p&gt;However, it is worth noting that this approach has its limitations. For example, it does not allow us to initialize the web component directly from pure HTML. Nevertheless, despite this limitation, this method can be extremely useful in cases where we pass data through JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Data Sources
&lt;/h2&gt;

&lt;p&gt;Now let’s imagine a situation where we are receiving data from some external source, and we don’t want to delve into its content or structure. We are confident in advance that the data coming from this source is in the appropriate format and is suitable for use in our component. In this case, the environment we build acts as a kind of breadboard, where the data source and the component that needs to receive and process that data are connected. It’s important to note that the environment does not need to understand the data being transferred, as it simply provides the mechanism for transferring the data, leaving the responsibility for data format to the components themselves.&lt;/p&gt;

&lt;p&gt;To better understand this idea, imagine we are connecting an external drive to a computer via a USB port. In this case, all we need to do is connect the cable, and the responsibility for correct data exchange between the devices lies with the drivers, which ensure that the device operates according to the appropriate protocol. We only need to make the connection without worrying about how the data is being transferred between the devices.&lt;/p&gt;

&lt;p&gt;Now, returning to web components, we can notice that if the environment doesn’t try to directly pass data to the component, but instead just connects the data source to the appropriate receiver, the entire system can become much simpler. Instead of passing large amounts of data, we can simply specify the source’s name, and the components will be able to obtain data from that source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-source&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;”source_id”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-component&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;”component_id”&lt;/span&gt; &lt;span class="na"&gt;source=&lt;/span&gt;&lt;span class="s"&gt;”source_id”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the component is not given the data itself, but merely a reference to the data source — its identifier. This identifier is a string, so this approach fully adheres to the constraints imposed by declarative HTML markup.&lt;/p&gt;

&lt;p&gt;The component needs to receive exactly as many identifiers as it will use data sources. By passing identifiers, we can use either attributes or properties. Thus, their number is minimized. If the same name is used for the attribute throughout the project, it can become a commonly understood and widely recognized name.&lt;/p&gt;

&lt;p&gt;The only thing to add here is that when developing the component, you should implement different behaviors depending on the data source, meaning you should develop a set of adapters that allow the component to connect to different data sources. Typically, such adapters are necessary not so much for working with sources, but for working with data formats. But we will discuss that later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If our goal is to create a universal web component, it should support both declarative approaches and dynamic data initialization. However, we must not forget that the declarative approach is primarily chosen to improve code readability, and in the pursuit of simplifying code reading, we might accidentally complicate the environment setup process, making it less flexible. It’s important to find the right balance between the flexibility of the component and the complexity of its declarative description.&lt;/p&gt;

&lt;p&gt;In my opinion, the best approach is not to pass data directly, but to organize interaction between components and data sources. This approach allows us to significantly simplify the architecture and make the code more modular and easily extensible. We will explore this approach in more detail in the next article.&lt;/p&gt;

&lt;p&gt;To improve development practices, I have taken the liberty of standardizing a few solutions in the KoiCom library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;KoiCom documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;KoiCom github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope it will be useful and provide you not only with ready-made solutions but also new ideas for development.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Initialization of a Web Component with External Data</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Thu, 23 Jan 2025 18:36:26 +0000</pubDate>
      <link>https://dev.to/valkoivo/initialization-of-a-web-component-with-external-data-2og3</link>
      <guid>https://dev.to/valkoivo/initialization-of-a-web-component-with-external-data-2og3</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/valkoivo/data-models-and-web-components-1jpa"&gt;previous article&lt;/a&gt;, we discussed why data encapsulation is a key characteristic of a well-designed web component. A web component, as a self-contained structure, should minimize external dependencies to ensure ease of use, portability, and testing. However, this encapsulation presents developers with a new challenge: if a component is "isolated," how can it be initialized using external data?&lt;/p&gt;

&lt;p&gt;This question opens up a whole range of fascinating challenges related to passing data into web components. Get ready — it’s going to be overly tedious, just the way you like it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialization of Web Components
&lt;/h2&gt;

&lt;p&gt;Initializing a web component is the process of getting a custom element ready to work within a web application. In simple terms, it involves creating an instance of a class registered with the customElements.define method and running the code defined in the component’s lifecycle methods, such as the constructor and connectedCallback.&lt;/p&gt;

&lt;p&gt;As we discussed in the previous article, during initialization, the component must establish its local state — essentially, the data object it will be working with. This object can be populated with default values, but more often than not, external data is needed to fill it.&lt;/p&gt;

&lt;p&gt;The component must somehow receive this external data, meaning the data has to be stored somewhere from the start. These data are passed to the component at the initialization stage. As a result, the component requires a specific environment that handles the preparation, storage, and transfer of the data, as well as kicks off the initialization process itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should the Environment Be Like?
&lt;/h2&gt;

&lt;p&gt;The simplest case of initialization is for an autonomous component. An autonomous component is independent of any environment or external factors, making it highly versatile. It can be integrated into any part of a document — whether it's a page with minimal structure or even a completely blank one. This approach significantly simplifies development because you don’t need to account for the specifics of the external environment, and testing becomes much easier. Developers can isolate the component and test it in a clean environment without needing to recreate the context. Not only does this save time, but it also eliminates potential risks that could arise from changes in the environment that might affect the component’s functionality.&lt;/p&gt;

&lt;p&gt;However, most components perform more complex tasks, including interacting with other elements or external data sources. For this, they require an environment. In such cases, it’s crucial that the environment maintains as much simplicity as possible. Ultimately, developers aim to combine the advantages of autonomous components with the ability to function within a more complex system. This can be achieved by ensuring that the environment remains as lightweight and user-friendly as possible, approaching the simplicity required for autonomous components.&lt;/p&gt;

&lt;p&gt;So, what characteristics should such an environment have? A simple environment is one that can be set up quickly, with minimal effort. For this to be the case, it should be understandable, compact, and familiar to the developer. When a developer faces a task that requires a minimal amount of action and uses widely accepted approaches and standards, the work becomes easier and faster to accomplish.&lt;/p&gt;

&lt;p&gt;For example, if you’re programming web components, you’ll immediately understand what the following code does. You’ll be able to either repeat it from memory or simply copy and paste it into your project without wasting much time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;some-component&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s why the key characteristics of a simple environment are the use of standard terminology and widely adopted approaches. The closer your code is to the standards, the easier it will be to understand, use, and deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Placement
&lt;/h2&gt;

&lt;p&gt;Let’s dive deeper into the topic of placing a component within an environment. What exactly do we mean by "placement"? Here, we’re referring to everything related to positioning: this could involve placing the module file of the component, the component's JavaScript code itself, or the HTML tag that adds the component to the page. Regardless of what we’re placing, it’s crucial that the placement rules are clear, understandable, and don’t require complex conditions to be followed.&lt;/p&gt;

&lt;p&gt;To understand why this is so important, let’s look at a typical example from standard HTML markup. We know that the &lt;strong&gt;li&lt;/strong&gt; tag should usually be inside a &lt;strong&gt;ul&lt;/strong&gt; tag. But what happens if we place the &lt;strong&gt;li&lt;/strong&gt; inside a &lt;strong&gt;div&lt;/strong&gt;? Or, conversely, if we nest a &lt;strong&gt;div&lt;/strong&gt; inside a &lt;strong&gt;ul&lt;/strong&gt;, and put the &lt;strong&gt;li&lt;/strong&gt; inside the &lt;strong&gt;div&lt;/strong&gt;? Here’s an example of such a structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this may seem like a small mistake, but this kind of rule violation can lead to unexpected consequences. Why? Because the HTML specification clearly defines rules for the placement of certain elements relative to each other. This creates additional questions and confusion, even with well-known tags.&lt;/p&gt;

&lt;p&gt;Now, imagine that we establish strict rules for placing our component within the environment. This could raise even more questions for developers, especially for those who are just starting to work with our component. For example, should the component only be placed in a specific section of the page? Do its neighboring elements need to follow certain conditions? Having strict placement rules can complicate working with the component.&lt;/p&gt;

&lt;p&gt;From this, we can draw an important conclusion: the environment will be simpler, and the component more user-friendly, if its use doesn’t depend on strict placement requirements. Ideally, a component should be flexible enough to be placed anywhere on the page without any additional conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Composition
&lt;/h2&gt;

&lt;p&gt;The more complex the composition of an environment, the higher its overall complexity. This is obvious: performing one operation is always easier than performing several. Each additional operation increases the chance of error, whether it's a forgotten action or an incorrectly executed step. Furthermore, the more steps involved in a process, the more time it takes, which affects overall performance.&lt;/p&gt;

&lt;p&gt;Let’s look at this in the context of working with components. When a component requires just one attribute to be specified, working with it is simple and intuitive. However, when a component requires setting five attributes at once, the task becomes significantly more difficult. It’s even more complicated if the values of some attributes depend on others. This interdependency increases the likelihood of errors and demands more attention from the developer.&lt;/p&gt;

&lt;p&gt;For example, I once worked with a component that required setting an initial value and boundary values. Although the boundary values had default values, I frequently forgot that they might not be suitable for the specific project. This led to errors that had to be fixed by going back to the documentation or rechecking the code. Here’s an example of such a component’s code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_maximum_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;maximum_value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;maximum_value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_initial_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initial_value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initial_value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;some-component&lt;/span&gt; &lt;span class="na"&gt;initial_value=&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you can see that the maximum_value attribute has a default value, but it can also be explicitly set. However, in real-world projects, default values don't always meet the current requirements. If this is overlooked, errors can occur that are not immediately obvious.&lt;/p&gt;

&lt;p&gt;From this, an important conclusion can be drawn: the fewer parts an environment has, the easier it is to work with. Every new element adds complexity, so minimizing the number of required configurations and dependencies helps make the process more understandable, convenient, and efficient. Design environments in such a way that they require minimal actions from the user to get started, and you will significantly simplify their use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing the Environment
&lt;/h2&gt;

&lt;p&gt;Let’s consider situations where a component needs to interact with its environment during initialization. To do so, the component must have the ability to access the environment — whether it's variables, objects, or events. However, for such interaction to be successful, the component must "know" its environment, or more precisely, have a clear way to identify it.&lt;/p&gt;

&lt;p&gt;A simple example: let’s assume the component needs to retrieve the content of another element. This can be done as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"some_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Some contents&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;some-component&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"asd"&lt;/span&gt; &lt;span class="na"&gt;div_id=&lt;/span&gt;&lt;span class="s"&gt;"some_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s not dive into the flaws of this code (and there are indeed several). Instead, let's focus on an important point: the component is accessing another element using a specific identifier (div_id). This approach simplifies the task because using a specific reference or name is the most intuitive way to interact with the environment. The component knows exactly where to look for the data, and it doesn’t need to scan the entire environment to find the required element.&lt;/p&gt;

&lt;p&gt;The same principle applies to events. If the component needs to intercept an event, it’s easiest for it to do so if it knows the code or name of the specific event it needs to handle. The clearer and more precise the point of interaction, the less likely an error will occur, and the easier the component’s integration process becomes.&lt;/p&gt;

&lt;p&gt;The key to simplifying a component’s interaction with the environment is having a variable, constant, or other mechanism that limits the scope of the search. If the component doesn’t need to "know" the entire environment but only needs to work with a specific part of it, the initialization process becomes much easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing the Environment
&lt;/h2&gt;

&lt;p&gt;Working with names is key to creating flexible and versatile components. When a component accesses something in its environment by name, switching from one environment to another becomes much easier if all that's needed is to replace the name. This approach minimizes the effort and reduces the chances of errors when adapting the component to new conditions.&lt;/p&gt;

&lt;p&gt;Let’s consider an example from the previous code. Suppose we want to use two components, each of which accesses its own unique &lt;strong&gt;div&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"some_id_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Some contents 1&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"some_id_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Some contents 2&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;some-component&lt;/span&gt; &lt;span class="na"&gt;div_id=&lt;/span&gt;&lt;span class="s"&gt;"some_id_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;some-component&lt;/span&gt; &lt;span class="na"&gt;div_id=&lt;/span&gt;&lt;span class="s"&gt;"some_id_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the implementation here is simple and clear. The components interact with different elements by simply getting their identifiers through the div_id attribute. This makes them universal and independent: by specifying a new name, you can easily reconfigure the component.&lt;/p&gt;

&lt;p&gt;Now imagine a situation where the &lt;strong&gt;div&lt;/strong&gt; identifier is "hard-coded" into the component’s code or, even worse, the component refers to a global variable. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;global_const&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;global_const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the component will always use the value of the global_const variable, regardless of the environment it's in. This creates a rigid dependence on the global state and complicates the adaptation process. If you need to change the behavior of the component, you’ll have to edit the code or modify global variables, which isn’t always convenient or safe.&lt;/p&gt;

&lt;p&gt;So, the important conclusion is this: an environment becomes simpler and more convenient if it provides the component with the ability to work with names that are easy to replace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Retrieval
&lt;/h2&gt;

&lt;p&gt;When a component interacts with its environment, the primary responsibility for the correctness of this process lies with the component itself. The component is the one that must use the name to access the necessary data. However, the environment also plays an important role: it must provide the data in a way that makes it easy for the component to use.&lt;/p&gt;

&lt;p&gt;Let’s consider an example from the previous code, where the component directly accesses a global variable. In this case, changing the environment name becomes very difficult because the component is tightly coupled to a specific variable. If a different variable is needed, the component code must be rewritten. This is not only inconvenient but also reduces the component's flexibility and reusability.&lt;/p&gt;

&lt;p&gt;Now, let’s improve the approach a bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;global_const&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;const_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;some-component&lt;/span&gt; &lt;span class="na"&gt;const_name=&lt;/span&gt;&lt;span class="s"&gt;"global_const"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/some-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this version, the component gets the variable name through the const_name attribute. This provides more flexibility: to use a different variable, it’s enough to pass a new name through the attribute. Of course, using the eval method is not an ideal solution. It carries potential security risks and can decrease performance. However, even this approach demonstrates how the environment change can be simplified by providing the component with a more convenient way to access data.&lt;/p&gt;

&lt;p&gt;This leads to another important rule: an environment becomes simpler if it offers the component a convenient and understandable way to access data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, I’ve tried to cover the key criteria that help assess the simplicity of the environment for initializing a web component. These criteria not only help to understand how easy it is to work with a component but also allow you to find ways to improve the interaction between the component and its environment. However, I’m sure that I haven’t covered all possible aspects. If you have any ideas, thoughts, or examples, I would be happy to consider them and include them in the article.&lt;/p&gt;

&lt;p&gt;In the next article, I plan to dive deeper into the topic and discuss specific approaches to data transfer between components. We will analyze them using the criteria of simplicity, convenience, and flexibility outlined here. This will help us choose the most effective and versatile methods suitable for a wide range of tasks and scenarios.&lt;/p&gt;

&lt;p&gt;Based on the best practices I identified during my work, I created the KoiCom library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;KoiCom documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;KoiCom github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It already incorporates the most successful ways to handle the interaction between components and their environment. I sincerely hope that this library will be useful to you and help simplify the development of web components. If you have any questions or feedback regarding its usage, I would be happy to hear from you.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Data Models and Web Components</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Sun, 19 Jan 2025 00:50:08 +0000</pubDate>
      <link>https://dev.to/valkoivo/data-models-and-web-components-1jpa</link>
      <guid>https://dev.to/valkoivo/data-models-and-web-components-1jpa</guid>
      <description>&lt;p&gt;Picture this: you've probably heard about web components multiple times — their magic, their unique ability to isolate through Shadow DOM. There are countless articles, endless webinars, and it feels as if the entire web development community is focused solely on one thing: isolating styles and markup. But what if I told you that this is merely the tip of the iceberg? That web components have far more capabilities, extending well beyond the Shadow DOM?&lt;/p&gt;

&lt;p&gt;Today, I want to take you beyond the surface and shine a light on something that often goes unnoticed: how web components handle data. Why does this topic get so little attention? Perhaps it’s because the official specification doesn’t highlight this potential. But once you start exploring, you’ll realize just how much is being overlooked.&lt;/p&gt;

&lt;p&gt;I apologize in advance if I start off slowly and become a bit tedious. It's necessary for the task at hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do Web Components Need Data?
&lt;/h2&gt;

&lt;p&gt;Web components are designed to be self-contained elements that can function independently from other parts of the system. This autonomy simplifies their integration into different areas of an application and allows for easy reuse across various projects. The key to this independence is encapsulation, which not only hides the component's appearance but also its internal behavior. This behavior, in turn, is tightly linked to how the component manages and uses data.&lt;/p&gt;

&lt;p&gt;For example, consider a calculator component designed to perform basic arithmetic operations. This component manages behavior such as displaying the current result, storing the previous result, and performing calculations. To achieve this, it maintains data such as the current result, the previous result, and settings like restrictions on input values.&lt;/p&gt;

&lt;p&gt;The data that web components use can be described as "local state." This local state stores essential information for the component's operation. It can include temporary data, intermediate calculation results, or other values needed to carry out specific tasks within the component.&lt;/p&gt;

&lt;p&gt;To begin with, let’s look at a simple example of how component properties can store basic data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleCalculator&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;previous_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="err"&gt;…&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;undo&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous_result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
  &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;The result is: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data in this example is often referred to as a "dumb" data model. Its main purpose is simply to store information without involving any complex logic. Despite its simplicity, this is a step forward because the data needed for the component’s operation is stored internally, avoiding the use of global variables.&lt;/p&gt;

&lt;p&gt;By keeping the data inside the component, we ensure that it’s isolated from the external system, meaning the component can function independently. Furthermore, to emphasize the encapsulation of the data, we prefix the property name with an underscore. This convention signals that the property is intended for internal use only and should not be accessed externally.&lt;/p&gt;

&lt;p&gt;So, what else can be achieved with this "dumb" model inside a component? One useful feature is caching. By storing data within the component, we can avoid unnecessary recalculations, redundant network requests, or other resource-heavy operations. In our example, saving the previous calculation result allows the implementation of an undo function, which improves performance and user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thick Model
&lt;/h2&gt;

&lt;p&gt;Is the "dumb" data model a universal solution for all cases? When working with simple components, it can indeed be sufficient. This model is easy to implement and handles basic data storage and processing tasks well. However, as the logic of the components becomes more complex, maintaining the "dumb" model becomes increasingly difficult. When a component involves multiple data operations, including modification and analysis, it makes sense to simplify the structure by separating this logic into distinct classes. One such approach is using a "thick" data model to isolate all data-related processes from the component itself.&lt;/p&gt;

&lt;p&gt;Let’s consider an example. A "thick" model can be represented by a separate class that stores the data and provides methods for modifying it. Within this model, not only can we store the result and the previous value, but we can also add auxiliary logic, such as automatically saving the previous result before any calculations. This greatly simplifies the component, freeing it from managing the data directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;previous_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;_rememberPreviousResult&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previous_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_rememberPreviousResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleCalculator&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_createModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;_createModel&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
  &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using the thick model, we not only encapsulate the data within the component, but we also hide some of the behavior from the component itself. The component is now unaware of both the data structure and the details of how data is set, modified, and retrieved. Its own behavior is simplified.&lt;/p&gt;

&lt;p&gt;With the introduction of the thick model, the component takes on the role of a controller. It manages the model but does not need to know its inner workings. As a result, the component no longer depends on the data structure or the methods used to process it. All it needs to know is the model’s interface — the set of methods it provides. This approach allows for easy replacement of one model with another.&lt;/p&gt;

&lt;p&gt;Moreover, the thick model becomes reusable: it can now be used not just in one component but in others as well, provided they work with similar data.&lt;/p&gt;

&lt;p&gt;For even greater flexibility, the Adapter pattern can be used. This pattern ensures compatibility between the component and the model, even if their interfaces initially differ. For example, if a component requires a model with additional logic, we can create an adapter to add this logic while maintaining the common interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CalculatorModelCapable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Sup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;_createModel&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
  &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleCalculator&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;CalculatorModelCapable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_createModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, for another component to work with the same model, it’s enough to apply this adapter. If we need to use a different model, we can either override its creation method or connect a different adapter. This ensures that the component remains unchanged, while its behavior is controlled by the model it’s connected to.&lt;/p&gt;

&lt;p&gt;Thus, separating the logic into a thick data model achieves several important goals. First, it makes the component lighter and easier to understand, leaving it only with management tasks. Second, the model becomes an independent and reusable element within the system. Third, using patterns like the Adapter ensures flexibility and scalability, allowing the data-handling logic to adapt to changing requirements. While this might seem overkill in simpler cases, it lays the foundation for building more complex and stable architectures in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decomposition of SSOT
&lt;/h2&gt;

&lt;p&gt;Let's explore the possibility of going even further in terms of organizing components and their interaction. Previously, we discussed how the autonomy of elements simplifies their integration into different parts of an application and makes them suitable for reuse in other projects. However, the autonomy of components opens up another interesting opportunity: it allows for the decomposition of the global Single Source of Truth (SSOT) and partially shifting it into individual components. This means that instead of having one global SSOT in the system, we can work with local SSOTs that encapsulate part of the logic and data.&lt;/p&gt;

&lt;p&gt;The idea is that splitting the global source of truth into local ones allows us to create components that are not only autonomous in their visual aspects but also have their own local logic necessary to perform their tasks. These components cease to be just visual elements and become independent mini-systems that manage their own data and behavior. This significantly increases their independence from the rest of the application, which in turn improves the stability and simplifies the evolution of the system.&lt;/p&gt;

&lt;p&gt;Moreover, when we talk about components, we are not limited to small UI elements like buttons, tables, or charts. A component can refer to more complex and larger application elements, such as a settings panel that combines several different functions, a registration or data entry form, or even a section with multiple interactive charts. Each of these components can have its own local source of truth, which manages the state and logic only within that specific element.&lt;/p&gt;

&lt;p&gt;The decomposition of SSOT into local parts simplifies the management of an application’s state. For example, instead of using a global source of truth for all form elements, we can encapsulate the state within the form, ensuring its independence from other parts of the application. This not only reduces the complexity of development but also makes the system more flexible, allowing components to be replaced or modified without requiring changes to the global logic.&lt;/p&gt;

&lt;p&gt;This approach to architectural design is especially useful in large-scale applications where global logic can become overloaded, and changes to one part of it can have cascading effects across the entire system. Local sources of truth help minimize such risks by creating isolated areas of responsibility, which simplifies maintenance and improves code readability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The ability of web components to store their own data allows us to see them as more than just simple visual elements of the interface. Now, they can be considered self-contained modules that integrate data, logic, and presentation. This approach makes components an effective tool for building application architecture. They can encapsulate complex behavior, manage their internal state, and organize interactions with other elements of the system at a higher level. This transforms web components into a versatile tool for creating flexible and scalable applications.&lt;/p&gt;

&lt;p&gt;To further develop the approach described here and significantly simplify my own tasks related to interface creation, I developed the KoiCom library, which is based on data management and data transfer between components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;KoiCom documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;KoiCom github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ultimately, I hope such solutions will help developers adopt a more modern approach to interface design, making applications more scalable and easier to maintain.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Next-Generation Buttons: Implementing the Command Pattern through Web Components</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Mon, 13 Jan 2025 20:08:28 +0000</pubDate>
      <link>https://dev.to/valkoivo/next-generation-buttons-implementing-the-command-pattern-through-web-components-3cne</link>
      <guid>https://dev.to/valkoivo/next-generation-buttons-implementing-the-command-pattern-through-web-components-3cne</guid>
      <description>&lt;p&gt;When I start designing an interface, I always encounter the issue that event handlers are directly attached to buttons, which limits the flexibility of component interaction. The problem is that standard buttons cannot offer any other behavior. What I need is logic isolation and dynamic action management, which are not available when using standard buttons 'out of the box.' In this article, I will propose a solution on how to adapt buttons using Web Components and the 'Command' pattern, opening new possibilities for more flexible and scalable interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Button is More Than It Seems
&lt;/h2&gt;

&lt;p&gt;Usually, when we think about a button, we perceive it as a graphical control element that provides a simple way to trigger some event, action, or change in the interface’s state. This is a very straightforward and convenient definition, which fits our everyday understanding of user interface elements in web applications.&lt;/p&gt;

&lt;p&gt;However, when we encounter a button in the context of web development, when HTML and JavaScript are involved, the first thing that comes to mind is the standard  tag, which is the most commonly used tool for creating buttons on web pages. This tag typically looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"myFunction()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if we think about it, this tag, while serving as a button, doesn't fully reflect all the possible aspects and functions that a button can perform in the broader context of user interaction with an interface.&lt;/p&gt;

&lt;p&gt;Upon closer inspection of the definition of a button, one might notice that it doesn't provide any information about how the button should look, how it should behave, or how it should trigger an action. In this context, there’s no clear understanding of what is meant by the words “a simple way” to trigger an action, nor how the connection between the button and the action is established. We only see the basic structure of a button, which, when clicked, calls some method. But in reality, this simplicity hides a much broader range of possibilities and approaches. And so, the question arises: perhaps the button is more than just the tag we see in the example above?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Way to Trigger an Action
&lt;/h2&gt;

&lt;p&gt;Let’s approach the concept of a button from a more philosophical perspective, delving into its essence and function. What does a button really represent? If we consider the essence of a jug as its emptiness, the essence of a button can be found in its ability to initiate an action. A button is not just a user interface element; it’s a mechanism that triggers a specific process that already exists within the context of the application. The action to be performed happens within the application, in the context of the entire system, but the initiation of that action — its start — is the button’s function. Therefore, we see that the button serves as a kind of trigger, launching an action in a broader external system context.&lt;/p&gt;

&lt;p&gt;When a user clicks on a button, they expect that this click will lead to a specific action. Consequently, the button is attributed with the responsibility for initiating this action. In other words, the button becomes the link between the user and the actions that should follow. However, it’s important to note that the method or function that actually carries out the action should not be aware that the button was the one that triggered it. This distinction between what initiates the action and what performs it is a crucial aspect that allows us to maintain flexibility and ease of interaction in more complex systems.&lt;/p&gt;

&lt;p&gt;When the button directly performs the action or when the method implementing the action depends on the button itself, we are dealing with a rather complex and interdependent system. If we wish to simplify such a system, it’s necessary to break it down into simpler, independent parts. And here we conclude that simplifying the process of initiating an action primarily involves separating the initiation process from the action itself. And since in the context of JavaScript, the initiator is often referred to as an event, we are talking specifically about separating the event as the initiator from the logic that executes the action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separation of Event and Handler
&lt;/h2&gt;

&lt;p&gt;Why is it important to separate the event from the handler?&lt;/p&gt;

&lt;p&gt;First of all, separating events from handlers significantly improves the readability of the code and promotes the creation of more modular solutions. When the button logic and its handler are intertwined, or, even worse, when the handler is an anonymous function, the code becomes extremely difficult to read and analyze. This can lead to problems when maintaining and updating the project, as understanding what the button actually does and what changes are required becomes a challenging task. In contrast, when the handler is extracted into a separate, well-named function that clearly reflects the action being performed, the structure of the code becomes more transparent. The developer immediately understands what happens when the button is clicked, and can more easily modify the behavior of the element without needing to delve into the rest of the logic. Thus, separation simplifies both reading and making changes to the code.&lt;/p&gt;

&lt;p&gt;Secondly, separating the event logic and the handler opens up opportunities for reusing handlers across different parts of the application. When the handler is placed in its own function, it can be applied not just to one button, but to many others that have similar behavior. For example, multiple buttons performing the same action can use the same handler, which reduces code duplication and increases efficiency. Furthermore, the handler can be triggered not only via the button but also through other means, such as programmatic calls or actions initiated by other parts of the interface. This significantly expands the functionality of your application, increasing its flexibility and scalability.&lt;/p&gt;

&lt;p&gt;Thirdly, separating events and handlers allows for more flexibility in the buttons themselves. If the behavior of the button is now determined not within the button itself, but via a separate handler, it becomes easy to modify its actions or reassign them depending on the situation. This is especially important in projects with dynamic interfaces, where the behavior of elements can change in response to user actions or changes in the application state. This approach allows the interface to be easily adapted to evolving requirements without disrupting the overall code structure.&lt;/p&gt;

&lt;p&gt;Fourthly, the separation of events and handlers is crucial for testability, particularly in large projects. When event handlers are extracted into separate functions, testing them becomes much easier, as they can be tested independently of the interface. You can isolate the handler and test how it works with various parameters, without worrying about interaction with other parts of the interface. This makes testing easier, improving the reliability and stability of the application while minimizing the likelihood of errors.&lt;/p&gt;

&lt;p&gt;Separating the button event and handler is a key step toward a cleaner, more flexible, and maintainable code architecture. This is especially important in complex projects, where the interactions between interface elements become more intricate and interdependent. This approach helps improve system stability, makes it easier to expand and modify the application, and reduces the risk of errors arising during these changes.&lt;/p&gt;

&lt;p&gt;An example of separating a button’s event from its handler can be found in any beginner’s guide.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"myButton"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button clicked!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Event Delegation
&lt;/h2&gt;

&lt;p&gt;There is a more elegant and efficient approach to handling events that greatly simplifies managing them in complex interfaces: event delegation. Instead of attaching an event listener to each button or element individually, you can intercept the event on a parent element or even at the document level. This is made possible by the bubbling property (bubbles: true), which allows an event to "bubble up" through the DOM tree from the target element to the root. This method offers several key advantages and can significantly streamline your code, making it more scalable and efficient.&lt;/p&gt;

&lt;p&gt;Event delegation is a technique where an event listener is assigned not to each individual element but to a common parent element that encompasses multiple child elements. When an event occurs on one of the child elements, it propagates to the parent, allowing the handler at the parent level to determine the source of the event (e.g., the target element via event.target) and execute the appropriate action. This approach reduces the number of event listeners in your code and enables centralized management of events for multiple elements.&lt;/p&gt;

&lt;p&gt;Event delegation is particularly useful in dynamic interfaces where elements like buttons or other controls are added to or removed from the DOM during the application’s lifecycle. In such cases, delegation enables you to handle events for elements added to the interface after the page has loaded, without needing to re-attach event listeners to new elements.&lt;/p&gt;

&lt;p&gt;Delegation is also ideal when dealing with a large number of similar elements in the DOM that require the same event handling logic. For example, if a page contains many buttons that should trigger the same action, delegation avoids attaching individual listeners to each button, resulting in cleaner and more optimized code. Furthermore, by reducing the number of event subscriptions, delegation lowers overhead, contributing to better performance.&lt;/p&gt;

&lt;p&gt;Like any technique, event delegation has its limitations. Firstly, it only works for events that support bubbling (such as click). Complex events that don’t bubble or need to be handled directly on the element may not be suitable for delegation. Secondly, in scenarios where handlers need to be tightly bound to specific elements — such as when unique parameters or contexts are required — delegation can become cumbersome and may not always be the best solution.&lt;/p&gt;

&lt;p&gt;For buttons, their events inherently support bubbling, so this limitation can be safely disregarded. However, the aspect of uniqueness, where specific actions are tied to particular elements, requires careful consideration and will be explored further later.&lt;/p&gt;

&lt;p&gt;In summary, event delegation is a powerful and flexible tool for managing events in complex interfaces. It enhances performance, simplifies code maintenance, and is especially valuable in scenarios where the DOM structure is dynamic or when dealing with numerous similar elements. If you encounter such challenges, event delegation is likely the optimal choice for improving efficiency and reducing code complexity.&lt;/p&gt;

&lt;p&gt;Here’s a simple example of event delegation. Imagine you have a list with several items, and you want to handle clicks on them using a single event listener:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;First Button&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Second Button&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button clicked!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bubbling Behavior of the click Event
&lt;/h2&gt;

&lt;p&gt;Have you ever wondered why the click event for buttons is designed to bubble up the DOM by default? At first glance, this might seem like a small detail, but it’s a thoughtful decision that has significantly simplified working with buttons in user interfaces. The reasoning lies in how buttons are used in real-world projects.&lt;/p&gt;

&lt;p&gt;Buttons are unique interface elements, and their characteristics make event bubbling especially important for them. Buttons play a key role in user interactions, triggering actions in various contexts. Event bubbling ensures flexibility, convenience, and efficiency when working with buttons, addressing several specific challenges.&lt;/p&gt;

&lt;p&gt;First, buttons are ubiquitous and frequently used. They appear in almost every interface, serving functions ranging from submitting forms to managing complex systems. Since buttons are often repeated and exist in large numbers, handling their events at the parent element level eliminates the need to create individual handlers for each button, simplifying code development and maintenance.&lt;/p&gt;

&lt;p&gt;Second, buttons are frequently created and removed dynamically. For instance, in task list interfaces or product card layouts, new buttons are added to the DOM based on user actions. Event bubbling allows developers to handle clicks on such buttons even when they are dynamically added or removed. This is particularly convenient because it eliminates the need for additional steps to attach handlers to newly created elements.&lt;/p&gt;

&lt;p&gt;Another important aspect of buttons is their dependency on context. For example, a button within a modal window might perform actions relevant only to that specific modal. Event bubbling makes it easy to consider context: you can set up a handler at the parent level or even at the document level while retaining the ability to determine which button was clicked and where it is located.&lt;/p&gt;

&lt;p&gt;Moreover, bubbling optimizes interface performance. If every button required its own event handler, this would significantly increase the number of event subscriptions, potentially reducing the responsiveness of the application — especially in interfaces with a large number of buttons. Bubbling enables developers to use a minimal number of handlers to manage events for a multitude of buttons, making the interface more efficient.&lt;/p&gt;

&lt;p&gt;Finally, buttons often perform similar actions. For example, "Add to Cart," "Delete Item," or "Open Menu" buttons typically share similar logic. Thanks to bubbling, developers can create universal handlers that work with any number of buttons without being tied to specific instances.&lt;/p&gt;

&lt;p&gt;In conclusion, buttons, as interface elements, possess unique characteristics that make event bubbling not just a convenient feature but an essential one. By leveraging bubbling, developers can create cleaner, more efficient, and more adaptable code, ensuring seamless interaction with buttons in both static and dynamic contexts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Payload
&lt;/h2&gt;

&lt;p&gt;We’ve established that button events should follow the bubbling pattern. Now, let’s take a closer look at what an event actually represents.&lt;/p&gt;

&lt;p&gt;In the DOM, an event object provides the context of an interaction, answering the question of how a specific action occurred. It describes the physical interaction between the user and the interface — for instance, a click on an element, text input, or a key press. However, it doesn’t address the more significant question: why the user initiated this interaction in the first place. Here lies a key contradiction: a user presses a button with a goal or intent in mind, while the event merely records the fact that a click occurred.&lt;/p&gt;

&lt;p&gt;When a user interacts with a button, they expect a specific action to be performed, such as "submit a form," "delete an item," or "save changes." To them, the button is a way to trigger a command. However, the click event triggered by the button only provides basic contextual information — such as which element was clicked, where it is located in the DOM, and potentially some custom data via CustomEvent. It conveys nothing about the user’s intent, leaving the interpretation of that intent entirely up to the handler.&lt;/p&gt;

&lt;p&gt;This gap between user intent and the technical representation of an event introduces additional complexity for developers. Developers must manually “bridge the gap,” connecting events to application logic using attributes like data-* or the detail property. This approach adds unnecessary coupling and complicates code maintenance, particularly in scalable interfaces with dynamic updates.&lt;/p&gt;

&lt;p&gt;For example, consider the following code snippet, which demonstrates an awkward implementation. Here, we have a button that, when clicked, is supposed to pass information about a selected item — such as its ID and name — via the event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buttonClicked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;elementName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example Item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCustomButtonClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elementName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;elementId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Name: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;elementName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buttonClicked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleCustomButtonClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If buttons could convey not only the context of an interaction but also the user's intent explicitly within the event, it would significantly simplify the architecture. Handlers could focus on executing tasks rather than assigning logic to events.&lt;/p&gt;

&lt;p&gt;This highlights the need to move away from the traditional understanding of a button as a mere event initiator. Instead, it suggests adopting a more advanced model where the button acts as a bridge between user intent and application logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Command Pattern
&lt;/h2&gt;

&lt;p&gt;To create a more advanced model for event handling, we can leverage the Command pattern, which allows events to be linked with application logic at a higher level of abstraction. This can be achieved by introducing a layer that transforms ordinary events into commands such as saveDocument or deleteItem. Using this approach, an event becomes more than just a signal that something has occurred — it transforms into what it is meant to be: the initiator of an action, as discussed earlier in the article.&lt;/p&gt;

&lt;p&gt;But this raises a question: why didn’t the developers of JavaScript events implement the Command pattern from the start? Why were events designed as they are now? And why were events necessary in the first place?&lt;/p&gt;

&lt;p&gt;When HTML and related technologies like the DOM and JavaScript were initially developed, their primary goal was to create a simple structure for hypertext documents that would allow users to interact with web pages. At that time, user interaction was significantly limited, and the event-handling model was not designed to accommodate complex mechanisms such as the Command pattern. It’s essential to understand that the early web was developed to simplify the creation and management of content, not to provide sophisticated tools for complex client-side logic.&lt;/p&gt;

&lt;p&gt;In the 1990s, when HTML and the web were being created, their focus was on providing a straightforward way to present hypertext documents with minimal user interaction. The main goal was data submission to servers rather than executing complex logic within the browser. Buttons and forms were primarily used to send data, not to initiate client-side processes. All computation and data processing were handled on the server, with buttons serving as interface elements that triggered data submission to the backend.&lt;/p&gt;

&lt;p&gt;The Command pattern requires a more sophisticated structure that involves clear separation between the interface and processing logic, as well as a mechanism to specify the exact action to be executed. These ideas only became relevant later, as the need for dynamic interfaces and greater interactivity in web applications grew. Dynamic and complex interactions, such as triggering client-side logic through events, necessitated new approaches, including the adoption of the Command pattern.&lt;/p&gt;

&lt;p&gt;Can the Command Pattern Be Applied to Buttons Today? Yes, it can. While standard HTML buttons don’t directly support the Command pattern, modern technologies like custom events allow us to create similar mechanisms. For example, we’ve already explored how the detail property can be used to pass additional data with events.&lt;/p&gt;

&lt;p&gt;However, this approach is still not ideal, as it requires creating separate implementations for each button in the interface. This adds extra complexity and makes scaling such systems more challenging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Components
&lt;/h2&gt;

&lt;p&gt;Leveraging Web Components to modernize buttons and align them with the Command pattern is a promising approach that can significantly enhance both the architecture and the flexibility of interactions in your project. Web Components provide powerful tools for creating reusable interface elements that can be seamlessly integrated into various parts of an application.&lt;/p&gt;

&lt;p&gt;Instead of writing separate handlers for each button, you can create a unified component that acts as a button with the added ability to pass a command. This approach not only improves the structure of the code but also enhances its readability and maintainability.&lt;/p&gt;

&lt;p&gt;Here’s a basic example of such a component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommandButton&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;commandExecuted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;bubbles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;composed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;button&amp;gt;Click me&amp;lt;/button&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;native_button_event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;native_button_event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;_onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;native_button_event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;command-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CommandButton&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;command-button&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"saveDocument"&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Save"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/command-button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Button Component and Controller
&lt;/h2&gt;

&lt;p&gt;When a button component transmits a command identifier and potentially additional parameters, it establishes the foundation for a more advanced architecture. In this setup, the component containing the button and subscribing to its events essentially acts as a controller that processes the command passed through the event.&lt;/p&gt;

&lt;p&gt;In architectural patterns such as MVC (Model-View-Controller), the controller serves as an intermediary between the model, which represents the data, and the view, which constitutes the user interface. It receives user input, such as button clicks, and manages the resulting changes to the data or state, which are then reflected in the interface.&lt;/p&gt;

&lt;p&gt;The use of a controller within a component offers several key advantages. First, it encapsulates the logic for executing commands, keeping the main application code free from unnecessary complexity. The details of implementation remain hidden within the controller itself. Second, this approach enhances modularity, allowing buttons to be reused simply by passing different commands and parameters. It also reduces the coupling within the application, as changes to the command-handling logic require modifications only within the controller, without affecting other parts of the system. Finally, controllers provide significant flexibility. They can handle both straightforward commands, such as "save" or "delete," and more complex actions, while the button component remains simple and focused solely on its primary role.&lt;/p&gt;

&lt;p&gt;This architecture facilitates a clean separation of concerns. The button component emits a custom event that includes the command and its relevant data, while the parent component, acting as the controller, listens for this event. The controller processes the command, interacts with the data model if necessary, and updates the user interface accordingly. This approach results in a cleaner, more scalable architecture that is easier to extend and maintain, while keeping the button components reusable and independent of the logic they trigger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, the approach where a button not only triggers an action but also transmits a command with the necessary data through an event is an excellent example of applying the "Command" pattern. This method significantly improves interface interaction organization by separating the logic of command execution from the interface elements, enhancing the flexibility and scalability of applications.&lt;/p&gt;

&lt;p&gt;However, such an approach is still relatively uncommon in practice. Instead of leveraging the powerful capabilities of Web Components to create universal and flexible solutions, many developers continue to rely on standard buttons directly tied to event handlers. This is likely due to habit and a lack of awareness about the advantages of this approach, leading to the more conventional use of buttons as simple triggers for actions.&lt;/p&gt;

&lt;p&gt;Determined to change this situation, I developed the KoiCom library, where many components have already been adapted and enhanced. In particular, buttons in this library follow the "Command" pattern, transmitting the necessary data and commands via events. This approach greatly increases modularity, flexibility, and maintainability, eliminating redundant logic and simplifying how commands are managed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;KoiCom documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;KoiCom github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ultimately, I hope such solutions will help developers adopt a more modern approach to interface design, making applications more scalable and easier to maintain.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>html</category>
      <category>es6</category>
    </item>
    <item>
      <title>Introducing KoiCom: A Library for Building Front-End Interfaces</title>
      <dc:creator>Valkoivo</dc:creator>
      <pubDate>Sat, 11 Jan 2025 13:47:23 +0000</pubDate>
      <link>https://dev.to/valkoivo/introducing-koicom-a-library-for-building-front-end-interfaces-5cfb</link>
      <guid>https://dev.to/valkoivo/introducing-koicom-a-library-for-building-front-end-interfaces-5cfb</guid>
      <description>&lt;p&gt;I'm excited to announce the release of KoiCom, a library designed for creating front-end interfaces using Web Components with a standardized lifecycle. The focus is on simplicity, transparency, and efficiency—perfect for headless applications or projects that need a streamlined workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;br&gt;
Component-Centric Design: KoiCom uses Web Components with a standardized lifecycle to simplify development and testing.&lt;br&gt;
Client-Side Execution: Interfaces built with KoiCom run entirely in the browser, interacting with servers only for data exchange.&lt;br&gt;
Framework-Free: No unnecessary abstractions—just functional, transparent, and simple code.&lt;br&gt;
Workflow Optimization: Enhances productivity without dictating component aesthetics, leaving styling to designers or frameworks like Bootstrap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Built KoiCom&lt;/strong&gt;&lt;br&gt;
I was inspired by the simplicity of the VCL library, which, despite its criticisms, excels at providing straightforward functionality for data manipulation. I wanted to build something similar but with a more modern foundation. Web Components were the perfect choice: widely supported, yet often underutilized.&lt;/p&gt;

&lt;p&gt;KoiCom addresses a key gap in existing tools: streamlined workflows without sacrificing clarity or independence from third-party frameworks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;br&gt;
📖 &lt;a href="https://valkoivo.github.io/koicom/index.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/valkoivo/koicom" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KoiCom is lightweight, easy to integrate, and offers a solid foundation for front-end development without overcomplicating things. I'd love to hear your feedback or see how you use KoiCom in your projects!&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>eventdriven</category>
    </item>
  </channel>
</rss>
