# How to create custom elements (Web Components) with ClojureScript?

**URL:** https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332
**Category:** How to?
**Tags:** clojurescript
**Created:** [June 4, 2019, 4:56pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332 "2019-06-04T16:56:39Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![jlesquembre](https://clojureverse.org/user_avatar/clojureverse.org/jlesquembre/32/3281_2.png) [@jlesquembre](https://clojureverse.org/u/jlesquembre)
#### Post date: [June 4, 2019, 4:56pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/1 "2019-06-04T16:56:39Z")

</div>

Custom elements rely on ES6 classes to be defined, a simple example in JS:

```javascript
class MyElement extends HTMLElement {}
customElements.define("my-element", MyElement)

```

See [Using custom elements on MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) for a detailed explanation

Since ES6 classes [cannot reliably be transpiled](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#Transpilers_versus_classes), and ClojureScript (as far as I know) doesn’t emit ES6 class syntax, the only way I can think of to generate a custom element is with [js\*](http://cljs.github.io/api/cljs.core/jsSTAR), e.g.:

```clojure
(def my-element (js* "class MyElement extends HTMLElement {}"))
(js/customElements.define "my-element" my-element)

```

Is there a better way? Or any plans to add support for ES6 classes in ClojureScript?

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [June 4, 2019, 8:30pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/2 "2019-06-04T20:30:02Z")

</div>

I played with web components a long while ago and I got it working fine, just needs a bit a macro sugar to make it look nicer. It might work differently nowadays since a lot may have changed in the 3 years since writing that.

> <https://gist.github.com/thheller/36332574918b974a3e4996efcb7457d2>

---

<div class="post-metadata">

### Author: ![KingMob](https://clojureverse.org/user_avatar/clojureverse.org/kingmob/32/352_2.png) [@KingMob](https://clojureverse.org/u/KingMob)
#### Post date: [June 5, 2019, 1:50pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/3 "2019-06-05T13:50:30Z")

</div>

Are you sure ClojureScript/Closure can’t emit ES6?

I haven’t tested it but the [:language-in and :language-out options](https://clojurescript.org/reference/compiler-options#language-in-and-language-out) seem like they would work with ES6.

The [Closure Compiler wiki](https://github.com/google/closure-compiler/wiki/ECMAScript6) definitely says it can handle ES6.

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [June 5, 2019, 1:56pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/4 "2019-06-05T13:56:50Z")

</div>

Closure handles ES6 just fine but ClojureScript has no built-in support to emit ES6 code (eg. `class`).

---

<div class="post-metadata">

### Author: ![jlesquembre](https://clojureverse.org/user_avatar/clojureverse.org/jlesquembre/32/3281_2.png) [@jlesquembre](https://clojureverse.org/u/jlesquembre)
#### Post date: [June 7, 2019, 4:30pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/5 "2019-06-07T16:30:53Z")

</div>

Thanks for the example, it is still working, the web component is created and attached to the DOM. 🙂

But I’m still trying to figure out how to mock some ES6 features. In many web components examples, apart of extending `HTMLElement`, the constructor is overridden (and `super()` is called) . So far I didn’t find a way of doing that with ClojureScript. Do you have more ClojureScript - Web Components examples?

For context, what I’m really trying to do is to create a ClojureScript wrapper around [LitElement](https://lit-element.polymer-project.org/)

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [June 10, 2019, 9:25am UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/6 "2019-06-10T09:25:16Z")

</div>

```auto
(defn component []
  (js/Reflect.construct js/HTMLElement #js [] component))

```

`component` is the constructor function and the `js/Reflect` call is basically the `super()` call. So this is basically `class component extends HTMLElement`.

---

<div class="post-metadata">

### Author: ![Mechrophile](https://clojureverse.org/letter_avatar_proxy/v4/letter/m/43a26b/32.png) [@Mechrophile](https://clojureverse.org/u/Mechrophile)
#### Post date: [June 11, 2019, 5:29pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/7 "2019-06-11T17:29:58Z")

</div>

@theller’s reply helped me out a bunch on this topic. For posterity, here’s my simple “render reagent/re-frame component as a webcomponent’s shadow DOM” function built out

> <https://gist.github.com/Mechrophile/163b04a414d63c10671fb46071b13d65>

---

<div class="post-metadata">

### Author: ![jlesquembre](https://clojureverse.org/user_avatar/clojureverse.org/jlesquembre/32/3281_2.png) [@jlesquembre](https://clojureverse.org/u/jlesquembre)
#### Post date: [June 17, 2019, 6:41am UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/8 "2019-06-17T06:41:34Z")

</div>

I just found that there is a ticket about adding support for ES6 classes to ClojureScript:  
[https://clojure.atlassian.net/browse/CLJS-3084](https://clojure.atlassian.net/browse/CLJS-3084)

---

<div class="post-metadata">

### Author: ![MageMasher](https://clojureverse.org/user_avatar/clojureverse.org/magemasher/32/916_2.png) [@MageMasher](https://clojureverse.org/u/MageMasher)
#### Post date: [June 26, 2019, 3:46pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/9 "2019-06-26T15:46:10Z")

</div>

This is really cool @Mechrophile! Works well!

---

<div class="post-metadata">

### Author: ![Jponline](https://clojureverse.org/user_avatar/clojureverse.org/jponline/32/2352_2.png) [@Jponline](https://clojureverse.org/u/Jponline)
#### Post date: [September 8, 2019, 1:54pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/10 "2019-09-08T13:54:50Z")

</div>

This seems very useful, but the gist is not available anymore. Does someone has the full snippet?

---

<div class="post-metadata">

### Author: ![Jponline](https://clojureverse.org/user_avatar/clojureverse.org/jponline/32/2352_2.png) [@Jponline](https://clojureverse.org/u/Jponline)
#### Post date: [September 9, 2019, 1:53am UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/11 "2019-09-09T01:53:15Z")

</div>

I might have found the Mechrophile full content, not sure if it’s exactly his version.

```
(ns simple-reagent-webcomponent (:require [reagent.core :as re]))
 
(defn webcomponent! [name view-component]
  (let [;; defines the constructor function, which is the "class" object used by the customElements api
        component (fn component [] (let [e
                                         ;; this is the equivalent of the call to "super"
                                         (js/Reflect.construct js/HTMLElement #js [] component)]
                           (js/console.log (str name ": Constructed!"))
                           (set! (.-shadow e) (.attachShadow e #js {:mode "open"}))
                           e))]
    (set! (.-prototype component)
          ;; establishes prototype hierarchy
          (js/Object.create (.-prototype js/HTMLElement)
                            #js {:connectedCallback
                                 #js {:configurable true
                                      :value (fn []
                                                      (this-as this
                                                        ;; attaches the reagent process to the shadow dom
                                                        (re/render [view-component] (.-shadow this))
                                                        (js/console.log (str name ": Connected! ") this)))}}))
 
    ;;finally, defines the component with these values
    (js/window.customElements.define name component)
 
    component))
 
(def globstate (re/atom 0))
 
(defn main-panel []
  [:div
   [:p "yo, dis a shadow dom p"]
   [:form
    [:p "Changes: " @globstate] [:br]
    "First Name: " [:input {:type :text
                            :name :fname
                            :on-change (fn [e] (.preventDefault e)
                                         (js/console.log "change!")
                                         (swap! globstate inc))}] [:br]]])
 
(defn init [] (webcomponent! "test-comp" main-panel))
```

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [March 9, 2020, 1:53pm UTC](https://clojureverse.org/t/how-to-create-custom-elements-web-components-with-clojurescript/4332/12 "2020-03-09T13:53:24Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
