{"id":13800822,"url":"https://github.com/dubiousdavid/dominator","last_synced_at":"2026-03-07T15:34:20.814Z","repository":{"id":29718325,"uuid":"33261423","full_name":"dubiousdavid/dominator","owner":"dubiousdavid","description":"Virtual-Dom in ClojureScript","archived":false,"fork":false,"pushed_at":"2015-06-09T02:00:38.000Z","size":1652,"stargazers_count":73,"open_issues_count":2,"forks_count":4,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-11-20T03:07:22.310Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dubiousdavid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-01T17:16:49.000Z","updated_at":"2022-01-31T01:05:59.000Z","dependencies_parsed_at":"2022-09-18T06:54:13.557Z","dependency_job_id":null,"html_url":"https://github.com/dubiousdavid/dominator","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dubiousdavid/dominator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dubiousdavid%2Fdominator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dubiousdavid%2Fdominator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dubiousdavid%2Fdominator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dubiousdavid%2Fdominator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dubiousdavid","download_url":"https://codeload.github.com/dubiousdavid/dominator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dubiousdavid%2Fdominator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30219541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T14:02:48.375Z","status":"ssl_error","status_checked_at":"2026-03-07T14:02:43.192Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:01:16.611Z","updated_at":"2026-03-07T15:34:20.774Z","avatar_url":"https://github.com/dubiousdavid.png","language":"JavaScript","funding_links":[],"categories":["Awesome ClojureScript"],"sub_categories":["Document Object Model"],"readme":"# Dominator\n\n[ClojureScript](https://github.com/clojure/clojurescript) + [Zelkova](https://github.com/jamesmacaulay/zelkova) + [Virtual Dom](https://github.com/Matt-Esch/virtual-dom) + [\"The Elm Pattern\"](http://elm-lang.org/) = Sane Javascript!\n\nUses [stch-html](https://github.com/stch-library/html) for representing HTML in ClojureScript.\n\n## Features\n\n* Single flow of events.\n* Use [core.async](https://github.com/clojure/core.async).\n* Use pure functions for updating state and rendering.\n* Minimal learning curve (i.e., easier than [Om](https://github.com/swannodette/om)).\n\n## Installation\n\n```clojure\n[com.2tothe8th/dominator \"0.4.0\"]\n```\n\nNote: You will need to download the compiled `vdom.js` file to your project directory and reference it in your HTML file.\n\n```bash\nwget https://raw.githubusercontent.com/dubiousdavid/dominator/master/vdom.js\n```\n\nYou will also need to add `:externs [\"dominator.js\"]` to the compiler options map if using advanced compilation.\n\n## Sample programs\n\n1. [Counter](http://dubiousdavid.github.io/dominator/examples/counter/) ([source](https://github.com/dubiousdavid/dominator/blob/master/examples/counter/src/counter/core.cljs))\n2. [Wikipedia](http://dubiousdavid.github.io/dominator/examples/wiki/) ([source](https://github.com/dubiousdavid/dominator/blob/master/examples/wiki/src/wiki/core.cljs))\n3. [Mario](http://dubiousdavid.github.io/dominator/examples/mario/) ([source](https://github.com/dubiousdavid/dominator/blob/master/examples/mario/src/mario/core.cljs))\n\n## API Documentation\n\nhttp://dubiousdavid.github.io/dominator/doc/\n\n## Example Usage\n\n### Overview\n\nIn the example below there is a single signal `actions` that all events are put onto. The `sig/reductions` function acts like an unending `reduce` over the `actions` signal. `reductions` takes a pure function, an initial value, and a signal, and produces a signal. `update-model` takes the existing model, the \"action\" (value from the signal), and returns a new model. The `view` function is mapped over each value from the `model` signal. This function returns a representation of the markup.  Finally the markup signal and root element are passed to `render`, which patches the DOM with each value from the signal (uses [requestAnimationFrame](ie.microsoft.com/testdrive/Graphics/RequestAnimationFrame) under the hood).\n\n```clojure\n(ns dominator.counter\n  (:require [dominator.core :refer [render]]\n            [stch.html :refer [div table tr td input]]\n            [cljs.core.async :as async :refer [\u003c!]]\n            [dominator.async :as as :refer-macros [forever]]\n            [dominator.test.util :as util]\n            [jamesmacaulay.zelkova.signal :as sig]\n            [cljs.core.match])\n  (:require-macros [cljs.core.match.macros :refer [match]]))\n\n(enable-console-print!)\n\n(def people [\"Billy\" \"Bobby\" \"Joey\"])\n(def actions (sig/write-port :no-op))\n\n(defn view [model]\n  (div\n    (table\n      (tr\n        (for [person people]\n          (td\n            (input :type \"button\" :value person\n                   :onclick (as/send actions [:clicked person])))))\n      (tr\n        (for [person people]\n          (td\n            (input :type \"text\" :readonly true :value (get model person))))))\n    (div :id \"button-row\"\n      (input :type \"button\" :value \"Reset\"\n             :onclick (as/send actions :reset)))))\n\n(def empty-model\n  {\"Billy\" 0\n   \"Bobby\" 0\n   \"Joey\" 0})\n\n(def initial-model\n  (or (util/get-storage \"clicks\") empty-model))\n\n(defn update-model [model action]\n  (match action\n    :no-op model\n    :reset empty-model\n    [:clicked n] (update-in model [n] inc)))\n\n(def model (sig/reductions update-model initial-model actions))\n(def modelc (sig/to-chan model))\n\n(render (sig/map view model) js/document.body)\n\n(forever\n  (let [m (\u003c! modelc)]\n    (util/set-storage \"clicks\" m)))\n```\n\n## Wikipedia search example\n\nBelow is a slightly more complicated example where we have two signals, one for actions and one for queries.\n\n```clojure\n(ns dominator.wiki\n  (:require [dominator.core :refer [render]]\n            [stch.html :refer [div input ul li]]\n            [cljs.core.async :as async :refer [\u003c! \u003e!]]\n            [dominator.async :as as :refer-macros [forever]]\n            [dominator.test.util :as util]\n            [clojure.string :as string]\n            [cljs.core.match]\n            [jamesmacaulay.zelkova.signal :as sig]\n            [jamesmacaulay.zelkova.time :as time])\n  (:require-macros [cljs.core.match.macros :refer [match]]))\n\n(enable-console-print!)\n\n(def wikipedia-endpoint\n  \"http://en.wikipedia.org/w/api.php?action=opensearch\u0026format=json\u0026search=\")\n\n(defn wikipedia [search]\n  (str wikipedia-endpoint search))\n\n(def query (sig/write-port \"\"))\n(def actions (sig/write-port :no-op))\n\n(defn view [results]\n  (div\n    (input :placeholder \"Search Wikipedia!\"\n           :oninput #(async/put! query (-\u003e % util/target-value string/trim)))\n    (ul\n      (for [result results]\n        (li result)))))\n\n(def empty-model [])\n\n(defn update-model [model action]\n  (match action\n    :no-op model\n    [:results results] results))\n\n(def queries\n  (-\u003e\u003e query\n       sig/drop-repeats\n       (time/debounce 150)\n       (sig/drop-if string/blank?)\n       (sig/map wikipedia)\n       sig/to-chan))\n\n(forever\n  (let [q (\u003c! queries)]\n    (let [result (\u003c! (util/jsonp q))]\n      (\u003e! actions [:results (second result)]))))\n\n(def model (sig/reductions update-model empty-model actions))\n\n(render (sig/map view model) js/document.body)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdubiousdavid%2Fdominator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdubiousdavid%2Fdominator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdubiousdavid%2Fdominator/lists"}