Components are registered via baredom.utils.component/register!, which creates the native ES class, wires lifecycle callbacks, and installs property accessors from a declarative options map. Do not create element-class functions manually — the factory handles all boilerplate.
(ns baredom.components.x-foo.x-foo
(:require [baredom.utils.component :as component]
[baredom.utils.dom :as du]
[baredom.components.x-foo.model :as model]))
;; Named lifecycle functions — always separate defn-, never inline
(defn- connected! [^js el] ...)
(defn- disconnected! [^js el] ...)
(defn- attribute-changed! [^js el _name old-val new-val] ...)
;; Property accessors — use du/install-properties! driven by model/property-api
(defn- install-property-accessors! [^js proto]
(du/install-properties! proto model/property-api))
(defn init! []
(component/register! model/tag-name
{:observed-attributes model/observed-attributes
:connected-fn connected!
:attribute-changed-fn attribute-changed!
;; Optional:
:disconnected-fn disconnected!
:form-associated? true
:setup-prototype-fn install-property-accessors!}))
Components install JS property accessors at one of three tiers. Pick the simplest tier the component qualifies for. Mixing tiers within one install-property-accessors! is fine; document and justify any drop to a lower tier inline.
One line:
(defn- install-property-accessors! [^js proto]
(du/install-properties! proto model/property-api))
Requires model/property-api to follow the canonical schema:
(def property-api
{:size {:type 'string :reflects-attribute attr-size :default "md"}
:open {:type 'boolean :reflects-attribute attr-open}
:delay {:type 'number :reflects-attribute attr-delay :default 400}})
Use Tier 0 when every property is a simple bool/string/number reflector with no custom logic. Methods (el.show()) and computed read-only properties don't fit property-api — if a component has those, drop to Tier 1.
Reference: x_icon (primary Golden Sample), x_button, x_i18n.
Use when most properties are simple but at least one needs a method or a custom parser:
(defn- install-property-accessors! [^js proto]
(du/install-properties! proto model/property-api) ;; data-reflective props
(aset proto "show" (fn [] (this-as ^js this (do-show! this))))
(aset proto "hide" (fn [] (this-as ^js this (do-hide! this)))))
Or keep it explicit when only a couple of helpers are needed:
(defn- install-property-accessors! [^js proto]
(du/define-bool-prop! proto "open" model/attr-open)
(du/define-string-prop! proto "label" model/attr-label)
(du/define-number-prop! proto "duration" model/attr-duration model/default-duration)
(custom-method! proto))
Reference: x_dropdown, x_combobox.
.defineProperty (last resort)Use only when helpers can't express the semantics:
el.src = "" should remove the attribute (e.g., x_image).el.open = true triggers an animation (e.g., x_drawer, x_modal).x_toaster's position keeps "" because (if v ...) is truthy on empty string.naturalWidth on x_image).:writable or :configurable flags.Document the reason inline so future readers understand why the tier dropped. Reference: x_image, x_currency_field, x_text_area.
defn- functions (connected!, disconnected!, attribute-changed!) — never inline anonymous functions for lifecycle.setup-prototype-fn should be a named defn- function (e.g. install-property-accessors!).this-as inside property getter/setter bodies — never reference this directly.when-not .get js/customElements).element-class functions with js* — use component/register! insteadjs/Reflect.construct with atom-based constructor wiringjs/Object.create / js/Object.setPrototypeOf prototype compositionCan you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |