{"id":15010328,"url":"https://github.com/borkdude/html","last_synced_at":"2026-06-13T12:01:17.387Z","repository":{"id":241289357,"uuid":"806184325","full_name":"borkdude/html","owner":"borkdude","description":"Html generation library inspired by squint's html tag","archived":false,"fork":false,"pushed_at":"2026-05-23T18:37:37.000Z","size":46,"stargazers_count":63,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-05-26T04:06:50.175Z","etag":null,"topics":["clojure","clojurescript","hiccup","html"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/borkdude.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"borkdude"}},"created_at":"2024-05-26T15:57:31.000Z","updated_at":"2026-05-23T23:15:50.000Z","dependencies_parsed_at":"2024-06-05T16:39:00.105Z","dependency_job_id":"a383c03f-2290-46d5-952a-cd4b81db662b","html_url":"https://github.com/borkdude/html","commit_stats":null,"previous_names":["borkdude/html"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/borkdude/html","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fhtml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fhtml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fhtml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fhtml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/borkdude","download_url":"https://codeload.github.com/borkdude/html/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fhtml/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34283391,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["clojure","clojurescript","hiccup","html"],"created_at":"2024-09-24T19:33:34.075Z","updated_at":"2026-06-13T12:01:17.322Z","avatar_url":"https://github.com/borkdude.png","language":"Clojure","funding_links":["https://github.com/sponsors/borkdude"],"categories":[],"sub_categories":[],"readme":"# html\n\nProduce HTML from hiccup in Clojure and ClojureScript.\n\n[![Clojars Project](https://img.shields.io/clojars/v/io.github.borkdude/html.svg)](https://clojars.org/io.github.borkdude/html)\n\n## Rationale\n\n[Squint](https://github.com/squint-cljs/squint) and\n[cherry](https://github.com/squint-cljs/cherry) support HTML generation as\nbuilt-in functionality. Some people wanted this functionality in JVM Clojure and\nClojureScript as well. That is what this library offers.\n\nBenefits over some (but definitely not all) hiccup libraries may be:\n\n- Generation of HTML is done at compile time, hiccup vectors are never inspected at runtime\n- The generated code is small and easy to understand\n- The library itself is small (currently around 100 lines of code)\n- The library works both in Clojure and ClojureScript\n\nDrawbacks of this library:\n\n- Less dynamic compared to other hiccup libraries (this can also seen as a benefit when it comes to security and performance)\n- New and thus not as mature and battle tested as other libraries. Issues + PRs welcome though\n- This library only outputs HTML5\n\nIn this README, all example results are written as strings. In reality they are\na `borkdude.html.Html` object which just contains a string. This is done to\nprevent issues with double-encoding.\n\n## Examples\n\n``` clojure\n(require '[borkdude.html :refer [html]])\n\n(let [name \"Michiel\"]\n  (html [:div {:color :blue :style {:color :blue}}\n         [:p \"Hello there \" name\n          [:ul\n           [:li 1]\n           (map (fn [i]\n                  (html [:li i]))\n                [2 3 4])]]]))\n;;=\u003e\n\"\u003cdiv color=\\\"blue\\\" style=\\\"color: blue;\\\"\u003e\u003cp\u003eHello there Michiel\u003cul\u003e\u003cli\u003e1\u003c/li\u003e\u003cli\u003e2\u003c/li\u003e\u003cli\u003e3\u003c/li\u003e\u003cli\u003e4\u003c/li\u003e\u003c/ul\u003e\u003c/p\u003e\u003c/div\u003e\"\n```\n\n## Passing props\n\nThis library doesn't support dynamic creation of attributes in the same way that\nsome hiccup libraries do. Rather, you have to use the special `:\u0026` property to\npass any dynamic properties, reminiscent of the JSX spread operator:\n\n``` clojure\n(let [m {:style {:color :blue} :class \"foo\"}]\n  (html [:div {:class \"bar\" :\u0026 m}]))\n;;=\u003e \"\u003cdiv class=\\\"foo\\\" style=\\\"color: blue;\\\"\u003e\u003c/div\u003e\"\n```\n\nAny static properties, like `:class \"bar\"` above function as a default which\nwill be overridden by the dynamic map `m`.\n\n## Fragment\n\nA fragment can be written in a similar way as JSX with `:\u003c\u003e` as the tag:\n\n``` clojure\n(html [:div [:\u003c\u003e \"Hello \" \"world\"]]) ;;=\u003e \u003cdiv\u003eHello world\u003c/div\u003e\n```\n\n## Unsafe\n\nUnsafe HTML (which won't be HTML-escaped) can be written with:\n\n``` clojure\n(html [:$ \"\u003cwhatever\u003e]) ;;=\u003e \"\u003cwhatever\u003e\"\n```\n\n## Child components\n\nJust use function calls for child components:\n\n``` clojure\n(defn child-component [{:keys [name]}]\n  (html [:div \"Hello \" name]))\n\n(defn App []\n  (html\n   [:div\n    [:div {:color :blue}]\n    (child-component {:name \"Michiel\"})]))\n\n(App) ;=\u003e \"\u003cdiv\u003e\u003cdiv color=\\\"blue\\\"\u003e\u003c/div\u003e\u003cdiv\u003eHello Michiel\u003c/div\u003e\u003c/div\u003e\"\n```\n\n## Child seqs\n\nTo render a sequence of child elements, use `html` to render the child element as well:\n\n``` clojure\n(html\n  [:ul\n    [:li 1]\n    (map (fn [i] (html [:li i])) [2 3])])\n;;=\u003e \"\u003cul\u003e\u003cli\u003e1\u003c/li\u003e\u003cli\u003e2\u003c/li\u003e\u003cli\u003e3\u003c/li\u003e\u003c/ul\u003e\"\n```\n\n## Performance\n\nDespite the relative simplicity of this library, performance is quite good. Here\nis an informal benchmark against `hiccup/hiccup`:\n\n``` clojure\n(comment\n  (defn ul []\n    (html [:ul [:li 1]\n           (map (fn [i]\n                  (html [:li i]))\n                [2 3])]))\n  (time (dotimes [_ 10000000] (ul))) ;; ~3600ms\n\n  (defn ul-hiccup []\n    (hiccup2.core/html [:ul [:li 1]\n                        (map (fn [i]\n                               [:li i])\n                             [2 3])]))\n  (time (dotimes [_ 10000000] (ul-hiccup))) ;; ~5500ms\n  )\n```\n\nNote that in `hiccup/hiccup`s case, when we wrap the `[:li i]` element within a\ncall to `hiccup2.core/html` as well, performance becomes similar as `html` since\nit can do a similar compile-time optimization.\n\n## Data reader\n\nTo install the `#html` reader, add the following to `data_readers.cljc`:\n\n``` clojure\n{html borkdude.html/html-reader}\n```\n\nThen you can write:\n\n``` clojure\n#html [:div \"Hello\"]\n```\n\nNote that these data readers aren't enabled by default since it's not recommended\nto use unqualified data readers for libraries since this can be a source of\nconflicts.\n\n## Complete HTML5 document\n\nWhen using `html`, this library outputs HTML5. So `[:br]` compiles to `\u003cbr\u003e`\nwithout a closing tag. Here is an example of how to to output a complete HTML5\ndocument:\n\n``` clojure\n(html\n [:\u003c\u003e\n  [:$ \"\u003c!DOCTYPE html\u003e\"]\n  [:html {:lang \"en\"}\n   [:head\n    [:meta {:charset \"utf-8\"}]\n    [:title \"Hi\"]]\n   [:body\n    [:div \"ok\"]\n    [:p\n     \"yes\"\n     [:br]]]]])\n```\n\n## License\n\nMIT, see `LICENSE`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborkdude%2Fhtml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fborkdude%2Fhtml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborkdude%2Fhtml/lists"}