{"id":21584,"date":"2018-05-03T12:15:24","date_gmt":"2018-05-03T09:15:24","guid":{"rendered":"https:\/\/www.webcodegeeks.com\/?p=21584"},"modified":"2018-05-03T10:27:42","modified_gmt":"2018-05-03T07:27:42","slug":"developing-web-components-in-scala-js","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/","title":{"rendered":"Developing Web Components in Scala.js"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the source and the destination language so that developers can write JavaScript-like code while benefiting from all the features of Scala. Scala.js seems to be quickly evolving, and is almost near the 1.0 release, which is the first production ready version.<\/p>\n<p>It is also catching up with the changing JavaScript syntax and APIs. For example, one interesting feature of Scala.js is the support of <a href=\"https:\/\/en.wikipedia.org\/wiki\/ECMAScript\">ES6<\/a> syntax which introduces things like classes and modules in JavaScript. ES6 syntax is required when developing <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Web_Components\">Web Components<\/a> based on the standard JavaScript APIs, and by supporting ES6, Scala.js offers the possibility to write reusable web components with nothing but standard JavaScript APIs. In this post, we will provide an example of writing web components in Scala.js, and how to combine web components to form a web application.<\/p>\n<h2>Components oriented approach<\/h2>\n<p>Following the modern front development paradigms, it is recommended to follow a components oriented approach or architecture when developing web applications for better modularity and separation of concerns. According to <a href=\"https:\/\/medium.com\/@dan.shapiro1210\/understanding-component-based-architecture-3ff48ec0c238\">Dan Shapiro<\/a>, components can be seen as a small feature that makes up a piece of the user interface.<\/p>\n<p>Components constitue the core functionality of several JavaScript frameworks like Angular and React. By using such frameworks, the developer can have a powerful set of tools at hand, however; this can create a lock-in and can lead to several issues in case breaking changes are introduced into the frameworks. Using the standard web component APIs can have its benefits in the way that the application has no dependencies and is somehow lightweight and easily adaptable to changes. In this example, we would like to develop an expense management application that allows adding, listing, and deleting expenses. As this is a demonstration, we want the application to use the browser\u2019s <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/localStorage\">local storage<\/a> for storing the data. We can imagine the structure of our application as follows:<\/p>\n<pre class=\"brush:xml\">&lt;app-element&gt;\r\n&lt;header-bar&gt;&lt;\/header-bar&gt;\r\n&lt;side-nav &gt;&lt;\/side-nav&gt;\r\n&lt;main-area &gt;\r\n    &lt;add-section&gt;&lt;\/add-section&gt;\r\n    &lt;list-section&gt;&lt;\/list-section&gt;\r\n    &lt;delete-section&gt;&lt;\/delete-section&gt;\r\n&lt;\/main-area&gt;\r\n&lt;\/app-element&gt;<\/pre>\n<p>Accordingly, we are going to develop the above components and glue them together to make up our application.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/05\/coa.png\"><img decoding=\"async\" class=\"aligncenter wp-image-21587\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/05\/coa.png\" alt=\"\" width=\"820\" height=\"414\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/05\/coa.png 1911w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/05\/coa-300x151.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/05\/coa-768x387.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/05\/coa-1024x517.png 1024w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<h2>Implementation<\/h2>\n<ul>\n<li>The setup:<\/li>\n<\/ul>\n<p>In addition to the basic Scala.js setup described in the <a href=\"https:\/\/www.scala-js.org\/tutorial\/basic\/\">documentation<\/a>, we are going to need to configure the Scala.js linker to produce ES6 (ECMAScript2015) JavaScript, so we need to add the following to the <code>build.sbt<\/code>:<\/p>\n<pre class=\"brush:scala\">scalaJSLinkerConfig ~= { _.withOutputMode(OutputMode.ECMAScript2015) }<\/pre>\n<p>Additionally, we need to enable Scala.js defined types (aka non native javascript types), to be exported to JavaScript by default by adding the following to the Scala build file:<\/p>\n<pre class=\"brush:scala\">scalacOptions += \"-P:scalajs:sjsDefinedByDefault\"<\/pre>\n<ul>\n<li>The missing pieces:<\/li>\n<\/ul>\n<p>Working with web components require some APIs that are not present by default in <a href=\"https:\/\/github.com\/scala-js\/scala-js-dom\"><code>scalajs-dom<\/code><\/a>, so we will need to write facade types for those before getting started. The first one is the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/CustomElementRegistry\/define\"><code>CustomElementsRegistry<\/code><\/a> object present in the global <code>Window<\/code> :<\/p>\n<pre class=\"brush:scala\">@js.native\r\n@JSGlobal\r\nclass Window extends dom.Window {\r\n\r\n   val customElements: CustomElementsRegistry = js.native\r\n\r\n}<\/pre>\n<p>CustomElementsRegistry definition:<\/p>\n<pre class=\"brush:scala\">@js.native\r\ntrait CustomElementsRegistry extends js.Any {\r\n   def define(name: String, definition: Any ) : Unit = js.native\r\n}<\/pre>\n<p>In this way we can register our custom elements by executing <code>window.customElements.define(\"add-section\", js.constructorOf[AddSectionElement])<\/code>, pretty much in the same way as described in the JavaScript <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Web_Components\/Using_custom_elements\">documentation<\/a><\/p>\n<p>Template and Shadow Dom are integral parts of the core specifications of web components and are important tools for developing web components. We are going to create the necessary objects and methods for enabling those as they are also missing from <code>scalajs-dom<\/code>.<\/p>\n<pre class=\"brush:scala\">@js.native\r\n@JSGlobal\r\nclass HTMLTemplateElement extends HTMLElement {\r\n\r\n  val content: HTMLElement = js.native\r\n}<\/pre>\n<p>and as the HTMLElement object misses the <code>attachShadow<\/code> method, we are going to extend it to add it:<\/p>\n<pre class=\"brush:scala\">@js.native\r\n@JSGlobal\r\nclass HTMLElement extends org.scalajs.dom.raw.HTMLElement {\r\n\r\n   def attachShadow(options: js.Any) : org.scalajs.dom.raw.HTMLElement = js.native\r\n\r\n}<\/pre>\n<p>We have now filled the missing gaps and we can start developing our components.<\/p>\n<ul>\n<li>The components:<\/li>\n<\/ul>\n<p>It is more convenient to use templates and <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Web_Components\/Using_templates_and_slots\">slots<\/a> instead of creating elements programatically.<\/p>\n<p>The <code>app-element<\/code> component connects between the side navigation <code>side-nav<\/code> bar element and the <code>main-area<\/code>. It needs to detect changes when a link is clicked on the side bar and route to the corresponding section. The custom elements specification defines <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Web_Components\/Using_custom_elements#Using_the_lifecycle_callbacks\">lifecycle callbacks<\/a> that are executed when a particular event occurs. For example, we use here <code>connectedCallback<\/code> to define the logic used by the component to route from a section to another. <code>connectedCallback<\/code> is invoked when the element is connected to DOM. The general guidelines (e.g <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/web-components\/customelements\">Google\u2019s guide to Custom Elements<\/a>) recommend to put all the setup code and logic inside the <code>connectedCallback<\/code>. Our <code>app-element<\/code> component looks like:<\/p>\n<p>template<\/p>\n<pre class=\"brush:xml\">&lt;template id=\"app-element-template\"&gt;\r\n&lt;slot name=\"header-bar\"&gt;&lt;\/slot&gt;\r\n&lt;slot name=\"side-nav\"&gt;&lt;\/slot&gt;\r\n&lt;slot name=\"main-area\"&gt;&lt;\/slot&gt;\r\n&lt;\/template&gt;<\/pre>\n<p>AppElement.scala<\/p>\n<pre class=\"brush:scala\">class AppElement extends HTMLElement {\r\n\r\n\r\n  var template: HTMLTemplateElement = dom.document.getElementById(\"app-element-template\").asInstanceOf[HTMLTemplateElement]\r\n  var shadow = this.attachShadow(JSON.parse(\"{\\\"mode\\\": \\\"open\\\"}\"));\r\n  shadow.appendChild(template.content.cloneNode(true));\r\n\r\n\r\n  def connectedCallback(): Unit  = {\r\n      initRouter()\r\n\r\n\r\n    var sections = getMainArea().getAllSections()\r\n\r\n    for (i &lt;- 0 until sections.length) {\r\n      var section = sections.item(i).asInstanceOf[MainAreaSectionElement]\r\n      getSideNav().addLink(section.getName())\r\n    }\r\n    updateUI()\r\n  }\r\n\r\n  private def getSideNav(): SideNavElement = {\r\n    return this.querySelector(\"side-nav\").asInstanceOf[SideNavElement]\r\n  }\r\n\r\n  private def getMainArea(): MainAreaElement = {\r\n    return this.querySelector(\"main-area\").asInstanceOf[MainAreaElement]\r\n  }\r\n\r\n\r\n  def initRouter(): Unit = {\r\n\r\n    dom.window.addEventListener(\"hashchange\", (event: Event)  =&gt; {\r\n\r\n      val hash = dom.window.location.hash.replace(\"#\", \"\")\r\n      getMainArea().select(hash)\r\n\r\n    }, false)\r\n  }\r\n\r\n  def updateUI(): Unit = {\r\n    val hash = dom.window.location.hash.replace(\"#\", \"\")\r\n    if ( !hash.isEmpty) {\r\n      getMainArea().select(hash)\r\n    } else {\r\n      getMainArea().selectFirst()\r\n    }\r\n  }\r\n}<\/pre>\n<p>Finally, for the component to work properly, it needs to be registered:<\/p>\n<pre class=\"brush:scala\">window.customElements.define(\"app-element\", js.constructorOf[AppElement])<\/pre>\n<ul>\n<li>Components reuse:<\/li>\n<\/ul>\n<p>Since Scala supports object oriented features like inheritence and polymorphism, our web components can use object orientation for better code usage and even more modularity. For example, the <code>list-section<\/code> and the <code>delete-section<\/code> both render a table with the current expenses. The difference between the two is that the <code>delete-section<\/code> needs to add a checkbox before each row to allow the user to select which expense to delete. Accordingly, we can make the <code>delete-section<\/code> inherit from the <code>list-section<\/code> element.<\/p>\n<p>template<\/p>\n<pre class=\"brush:xml\">&lt;template id=\"main-area-section-template\"&gt;\r\n    &lt;!-- styles where omitted for better readabiltiy --&gt;\r\n     &lt;section&gt; \r\n         &lt;div class=\"container\"&gt;\r\n\r\n         &lt;\/div&gt;\r\n    &lt;\/section&gt;\r\n&lt;\/template&gt;<\/pre>\n<p>ListSectionElement.scala<\/p>\n<pre class=\"brush:scala\">class ListSectionElement extends MainAreaSectionElement {\r\n\r\n  var dataTable: HTMLTableElement = null;\r\n  setName(\"List\")\r\n\r\n  def connectedCallback(): Unit  = {\r\n    renderTable()\r\n  }\r\n\r\n  def renderTable(): Unit = {\r\n\r\n    dataTable = dom.document.createElement(\"table\").asInstanceOf[HTMLTableElement]\r\n    dataTable.classList.add(\"data-table\")\r\n    val tableHeader = dom.document.createElement(\"thead\").asInstanceOf[HTMLElement]\r\n    val idHeaderCell = dom.document.createElement(\"th\").asInstanceOf[HTMLElement]\r\n    idHeaderCell.textContent = \"id\"\r\n    val amountHeaderCell = dom.document.createElement(\"th\").asInstanceOf[HTMLElement]\r\n    amountHeaderCell.textContent = \"amount\"\r\n    val dateHeaderCell = dom.document.createElement(\"th\").asInstanceOf[HTMLElement]\r\n    dateHeaderCell.textContent = \"date\"\r\n    val reasonHeaderCell = dom.document.createElement(\"th\").asInstanceOf[HTMLElement]\r\n    reasonHeaderCell.textContent = \"reason\"\r\n\r\n    val tableHeaderRow = dom.document.createElement(\"tr\").asInstanceOf[HTMLTableRowElement]\r\n\r\n    tableHeaderRow.appendChild(idHeaderCell)\r\n    tableHeaderRow.appendChild(amountHeaderCell)\r\n    tableHeaderRow.appendChild(dateHeaderCell)\r\n    tableHeaderRow.appendChild(reasonHeaderCell)\r\n\r\n    tableHeader.appendChild(tableHeaderRow)\r\n    dataTable.appendChild(tableHeader)\r\n\r\n    for (i &lt;- 0 until dom.window.localStorage.length ) {\r\n      val key = dom.window.localStorage.key(i)\r\n      val expenseJsonOption = Option(dom.window.localStorage.getItem(key))\r\n      if (expenseJsonOption.isDefined) {\r\n      val expense = decode[Expense](expenseJsonOption.get).toSeq.last\r\n          val row = dom.document.createElement(\"tr\").asInstanceOf[HTMLTableRowElement]\r\n          val idCell = dom.document.createElement(\"td\").asInstanceOf[HTMLTableDataCellElement]\r\n          idCell.textContent = expense.id\r\n          val amountCell = dom.document.createElement(\"td\").asInstanceOf[HTMLTableDataCellElement]\r\n          amountCell.textContent = expense.amount\r\n          val dateCell = dom.document.createElement(\"td\").asInstanceOf[HTMLTableDataCellElement]\r\n          dateCell.textContent = expense.date\r\n          val reasonCell = dom.document.createElement(\"td\").asInstanceOf[HTMLTableDataCellElement]\r\n          reasonCell.textContent = expense.reason\r\n          row.appendChild(idCell)\r\n          row.appendChild(amountCell)\r\n          row.appendChild(dateCell)\r\n          row.appendChild(reasonCell)\r\n          dataTable.appendChild(row)\r\n      }\r\n    }\r\n    getContainer().appendChild(dataTable)\r\n  }\r\n\r\n  def refreshUI(): Unit = {\r\n    clear()\r\n    renderTable()\r\n  }\r\n}<\/pre>\n<p>DeleteSectionElement.scala:<\/p>\n<pre class=\"brush:scala\">class DeleteSectionElement extends ListSectionElement {\r\n\r\n  setName(\"Delete\")\r\n\r\n  override def connectedCallback(): Unit  = {\r\n       this.renderTable()\r\n  }\r\n\r\n  override def renderTable(): Unit = {\r\n    super.renderTable()\r\n    val rows = dataTable.querySelectorAll(\"tr\")\r\n\r\n    val headerRow = dataTable.querySelector(\"thead &gt; tr\").asInstanceOf[HTMLTableRowElement]\r\n    val emptyHeaderCell = dom.document.createElement(\"th\")\r\n    headerRow.insertBefore(emptyHeaderCell, headerRow.firstChild)\r\n\r\n    for (i &lt;- 1 until rows.length) {\r\n      val row = rows.item(i)\r\n      val deleteCell = dom.document.createElement(\"td\").asInstanceOf[HTMLTableDataCellElement]\r\n      val deleteCheckBox = dom.document.createElement(\"input\").asInstanceOf[HTMLInputElement]\r\n      deleteCheckBox.`type` = \"checkbox\"\r\n      deleteCheckBox.id = row.firstChild.textContent\r\n      deleteCell.appendChild(deleteCheckBox)\r\n      row.insertBefore(deleteCell, row.firstChild)\r\n    }\r\n\r\n    val deleteButton = dom.document.createElement(\"button\").asInstanceOf[HTMLButtonElement]\r\n    deleteButton.textContent = \"Delete selection\"\r\n    deleteButton.classList.add(\"action-button\")\r\n\r\n    deleteButton.addEventListener(\"click\", (event:Event) =&gt; {\r\n      val rows = dataTable.querySelectorAll(\"tr\")\r\n      for (i &lt;- 1 until rows.length) {\r\n        val row = rows.item(i)\r\n        val input = row.asInstanceOf[HTMLTableRowElement].querySelector(\"td &gt; input\").asInstanceOf[HTMLInputElement]\r\n        if (input.checked) {\r\n          dom.window.localStorage.removeItem(input.id)\r\n        }\r\n      }\r\n      dom.document.dispatchEvent(new wrappers.Event(\"deleteExpense\"))\r\n    })\r\n\r\n    getContainer().appendChild(deleteButton)\r\n  }\r\n\r\n  override def refreshUI(): Unit = {\r\n    clear()\r\n    renderTable()\r\n  }\r\n}<\/pre>\n<p>we can notice that <code>DeleteSectionElement<\/code> not only uses the same table used by its parent <code>ListSectionElement<\/code>, but also makes use of the render method and overrides it. Since <code>AddSectionElement<\/code> (implementation can be found in the source code), <code>ListSectionElement<\/code>, and <code>DeleteSectionElement<\/code> all constitute sections of the <code>main-area<\/code> and share the same template and the same initialization code, we can create a parent element for all of them to factorize the common initialization code and methods:<\/p>\n<pre class=\"brush:scala\">abstract class MainAreaSectionElement extends HTMLElement {\r\n\r\n  var template: HTMLTemplateElement = dom.document.getElementById(\"main-area-section-template\").asInstanceOf[HTMLTemplateElement]\r\n  var shadow = this.attachShadow(JSON.parse(\"{\\\"mode\\\": \\\"open\\\"}\"))\r\n  shadow.appendChild(template.content.cloneNode(true))\r\n\r\n\r\n  def getContainer(): Element = {\r\n    return this.shadow.querySelector(\".container\")\r\n  }\r\n\r\n  def setName(name: String): Unit = {\r\n    this.setAttribute(\"name\", name)\r\n  }\r\n\r\n  def getName(): String = {\r\n    this.getAttribute(\"name\")\r\n  }\r\n\r\n  def clear(): Unit = {\r\n    var firstChild = getContainer().firstChild\r\n    while(firstChild != null) {\r\n      getContainer().removeChild(firstChild)\r\n      firstChild = getContainer().firstChild\r\n    }\r\n  }\r\n\r\n}<\/pre>\n<p>We have made <code>MainAreaSectionElement<\/code> abstract to prevent its initiaization and force elements to inherit from it. The <code>clear<\/code>, <code>getContainer<\/code>, <code>setName<\/code>, <code>getName<\/code>, <code>clear<\/code> are used\/overrided by all the child elements.<\/p>\n<p>We have seen how object orientation helped us effectively design and implement all <code>*-section<\/code> elements which is something the would not have been possible with the plain JavaScript implementation.<\/p>\n<ul>\n<li>Components communication:<\/li>\n<\/ul>\n<p>Components can communicate into different ways like custom events and by invoking each others methods. For example, when adding a new expense we need to tell the <code>list-section<\/code> and the <code>delete-section<\/code> to re-render because a new element was added. Same goes for when deleting an expense. To do so, we have created custom events called <code>addExpense<\/code> and <code>deleteExpense<\/code> that we dispatch each time these events occur:<\/p>\n<pre class=\"brush:scala\">dom.document.dispatchEvent(new wrappers.Event(\"deleteExpense\"))<\/pre>\n<p>At the level of the <code>main-area<\/code> element, we listen to the events and take the appropriate actions:<\/p>\n<pre class=\"brush:scala\">dom.document.addEventListener(\"deleteExpense\", (event: Event) =&gt; {\r\n      getListSection().refreshUI()\r\n      getDeleteSection().refreshUI()\r\n    })<\/pre>\n<p>Another way of communication between components is by invoking each others methods. For example, the <code>app-element<\/code> listens to hash link changes and asks the <code>main-area<\/code> to select the desired section :<\/p>\n<pre class=\" brush:scala\">dom.window.addEventListener(\"hashchange\", (event: Event)  =&gt; {\r\n\r\n      val hash = dom.window.location.hash.replace(\"#\", \"\")\r\n      getMainArea().select(hash)\r\n\r\n    }, false)<\/pre>\n<ul>\n<li>Cross-Browser compatibility:<\/li>\n<\/ul>\n<p>Not all browser support web components by default (Only Chrome and Opera by default). A web component polyfill needs to be added in case the app is to be run on other browsers. More details can be found in the github repository page: <a href=\"https:\/\/github.com\/WebComponents\/webcomponentsjs\">https:\/\/github.com\/WebComponents\/webcomponentsjs<\/a><\/p>\n<h2>Wrap up<\/h2>\n<p>By supporting ES6, Scala.js opens a wide range of possiblities: using web components is one of them. The possibility of using web components makes Scala.js an attractive alternative for developing web applications while staying in the confort of the Scala language and benefiting from the support of IDEs.<\/p>\n<p>source code: <a href=\"https:\/\/github.com\/gwidgets\/scalajs-webcomponents-demo\">https:\/\/github.com\/gwidgets\/scalajs-webcomponents-demo<\/a><br \/>\nRunning app: <a href=\"https:\/\/gwidgets.github.io\/scalajswebcomponents\">https:\/\/gwidgets.github.io\/scalajswebcomponents<\/a><\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>Published on Web Code Geeks with permission by Zakaria Amine, partner at our <a href=\"\/\/www.webcodegeeks.com\/join-us\/wcg\/\" target=\"_blank\" rel=\"noopener\">WCG program<\/a>. See the original article here: <a href=\"http:\/\/www.g-widgets.com\/2018\/05\/02\/developing-web-components-in-scala-js\/\" target=\"_blank\" rel=\"noopener\">Developing Web Components in Scala.js<\/a><\/p>\n<p>Opinions expressed by Web Code Geeks contributors are their own.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the source and the destination language so that developers can write JavaScript-like code while benefiting from all the features of Scala. Scala.js seems to be quickly evolving, and is almost near the 1.0 release, &hellip;<\/p>\n","protected":false},"author":4470,"featured_media":920,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[115],"class_list":["post-21584","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","tag-scala-js"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Developing Web Components in Scala.js - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Developing Web Components in Scala.js - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2018-05-03T09:15:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Zakaria Amine\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Zakaria Amine\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\"},\"author\":{\"name\":\"Zakaria Amine\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/ce5305c30531ff9e0144e637858512c5\"},\"headline\":\"Developing Web Components in Scala.js\",\"datePublished\":\"2018-05-03T09:15:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\"},\"wordCount\":1159,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg\",\"keywords\":[\"Scala.js\"],\"articleSection\":[\"JavaScript\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\",\"name\":\"Developing Web Components in Scala.js - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg\",\"datePublished\":\"2018-05-03T09:15:24+00:00\",\"description\":\"Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/javascript\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Developing Web Components in Scala.js\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/ce5305c30531ff9e0144e637858512c5\",\"name\":\"Zakaria Amine\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/f57181b135803b2a4b6f52e1b555b6f969d1e28d098fb9f61ab466d7ed368d94?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/f57181b135803b2a4b6f52e1b555b6f969d1e28d098fb9f61ab466d7ed368d94?s=96&d=mm&r=g\",\"caption\":\"Zakaria Amine\"},\"description\":\"Zakaria is a freelance software engineer who enjoys working with Java web frameworks, and microservice architectures. During his free time, Zakaria works on hobby projects, and blogs about his favorite topics like GWT and Spring.\",\"sameAs\":[\"http:\/\/www.g-widgets.com\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/zakaria-amine\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Developing Web Components in Scala.js - Web Code Geeks - 2026","description":"Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/","og_locale":"en_US","og_type":"article","og_title":"Developing Web Components in Scala.js - Web Code Geeks - 2026","og_description":"Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the","og_url":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2018-05-03T09:15:24+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg","type":"image\/jpeg"}],"author":"Zakaria Amine","twitter_card":"summary_large_image","twitter_creator":"@webcodegeeks","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Zakaria Amine","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/"},"author":{"name":"Zakaria Amine","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/ce5305c30531ff9e0144e637858512c5"},"headline":"Developing Web Components in Scala.js","datePublished":"2018-05-03T09:15:24+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/"},"wordCount":1159,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg","keywords":["Scala.js"],"articleSection":["JavaScript"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/","url":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/","name":"Developing Web Components in Scala.js - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg","datePublished":"2018-05-03T09:15:24+00:00","description":"Introduction Scala.js is a compiler that allows producing JavaScript from Scala. It focuses on simplicity and the elimination of borders between the","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/js-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/javascript\/developing-web-components-in-scala-js\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"JavaScript","item":"https:\/\/www.webcodegeeks.com\/category\/javascript\/"},{"@type":"ListItem","position":3,"name":"Developing Web Components in Scala.js"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/ce5305c30531ff9e0144e637858512c5","name":"Zakaria Amine","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/f57181b135803b2a4b6f52e1b555b6f969d1e28d098fb9f61ab466d7ed368d94?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f57181b135803b2a4b6f52e1b555b6f969d1e28d098fb9f61ab466d7ed368d94?s=96&d=mm&r=g","caption":"Zakaria Amine"},"description":"Zakaria is a freelance software engineer who enjoys working with Java web frameworks, and microservice architectures. During his free time, Zakaria works on hobby projects, and blogs about his favorite topics like GWT and Spring.","sameAs":["http:\/\/www.g-widgets.com"],"url":"https:\/\/www.webcodegeeks.com\/author\/zakaria-amine\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/21584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/4470"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=21584"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/21584\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/920"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=21584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=21584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=21584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}