From c7ab26a2092dfb1cafc9b80ec42fce3833e84c48 Mon Sep 17 00:00:00 2001 From: Jake Zerrer Date: Mon, 14 Sep 2026 11:44:12 -0400 Subject: [PATCH] Merge shorthand classes when the attribute map has no :class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `merge-attrs` only merged the shorthand classes from a tag like `:div.card` when the attribute map ALSO carried a `:class` key — the outer `if-let` tested the map's class, not the shorthand's. So [:div.card {:id "a"}] =>
silently lost the class, while [:div.card {:class "big"}] =>
worked. The same expression also interpolated at macroexpansion time, so a `:class` bound to anything non-constant rendered the symbol's NAME: (let [x "big"] [:div.card {:class x}]) => class="card x" --- CHANGELOG.md | 4 ++++ src/borkdude/html.cljc | 21 +++++++++++---------- test/borkdude/html_test.cljc | 13 +++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 803b8d2..e97b8ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Unreleased changes are available via `io.github.borkdude/html {:git/sha "..."}` [html](https://github.com/borkdude/html): Produce HTML from hiccup in Clojure and ClojureScript +## Unreleased + +- Fix shorthand classes being dropped when the attribute map has no `:class`: `[:div.card {:id "a"}]` rendered `
`. The same path interpolated a symbol's _name_ when `:class` was bound to an expression, so `(let [x "big"] [:div.card {:class x}])` rendered `class="card x"`. + ## 0.2.6 - Fix [#17](https://github.com/borkdude/html/issues/17): inline `style` map emitted a literal `\n` between declarations via `pr-str`, producing invalid CSS that dropped every declaration after the first ([@cycl1st](https://github.com/cycl1st)) diff --git a/src/borkdude/html.cljc b/src/borkdude/html.cljc index b0652ef..ae41c26 100644 --- a/src/borkdude/html.cljc +++ b/src/borkdude/html.cljc @@ -93,14 +93,16 @@ (.substring tag (unchecked-inc-int class-index)))])) (defn merge-attrs [attrs short-attrs] - (let [attrs (if-let [c (:class attrs)] - (if-let [sc (:class short-attrs)] - (assoc attrs :class (str sc " " c)) - attrs) - attrs) + (let [attrs (if-let [sc (:class short-attrs)] + (if-let [c (:class attrs)] + (assoc attrs :class (if (constant? c) + (str sc " " c) + `(str ~sc " " ~c))) + (assoc attrs :class sc)) + attrs) attrs (if-let [id (:id short-attrs (:id attrs))] - (assoc attrs :id id) - attrs)] + (assoc attrs :id id) + attrs)] attrs)) (defn- ->html [opts form] @@ -174,8 +176,7 @@ (html [:div [:<> "hello " "there"]]) (html [:div [[:<>script]]]) (html [:div [:$ [:<>script]]]) - (macroexpand-all '(html [:div ])) + (macroexpand-all '(html [:div])) (macroexpand-all '(html [:div "Hello"])) (html [:br]) - (xml [:br]) - ) + (xml [:br])) diff --git a/test/borkdude/html_test.cljc b/test/borkdude/html_test.cljc index 9db71d4..b93bdca 100644 --- a/test/borkdude/html_test.cljc +++ b/test/borkdude/html_test.cljc @@ -94,6 +94,19 @@ "" (html [:a#foo.bar.baz {:class "quux"}]) + "
" + (html [:div.card {:id "a"}]) + + "
" + (html [:div.card {}]) + + "
" + (let [x "big"] + (html [:div.card {:class x}])) + + "
" + (html [:div.card {:class (str "bi" "g")}]) + "
" (html [:div {:style {:color :blue}}])