       (str/join " " cs))))
 
 
-(defn render-attr [[name value]]
-  (let [name (as-str name)]
+(defn render-attr! [name value sb]
+  (let [name (to-str name)]
     (cond
-      (true? value)    (str " " name "=\"\"")
-      (not value)      ""
+      (true? value)    (append! sb " " name "=\"\"")
+      (not value)      :nop
       (= "style" name) (let [style (render-style value)]
-                         (if (str/blank? style)
-                           ""
-                           (str " style=\"" style "\"")))
+                         (when-not (str/blank? style)
+                           (append! sb " style=\"" style "\"")))
       (= "class" name) (when-let [value (normalize-classes value)]
-                         (str " class=\"" value "\""))
-      :else            (str " " name "=\"" (as-str value) "\""))))
-
-
-(defn render-attr-map [attrs]
-  (->> attrs
-    (map render-attr)
-    (str/join "")))
+                         (append! sb " class=\"" value "\""))
+      :else            (append! sb " " name "=\"" (to-str value) "\""))))
+
+
+(defn render-attrs! [attrs sb]
+  (doseq [[key value] attrs]
+    (render-attr! key value sb)))
 
 
 ;;; render html
 
 
 (defprotocol HtmlRenderer
-  (-render-html [this parent *key]
+  (-render-html [this parent *key sb]
     "Turn a Clojure data type into a string of HTML with react ids."))
 
 
 (defn -render-element
   "Render an element vector as a HTML element."
-  [element *key]
+  [element *key sb]
   (let [[tag attrs content] (normalize-element element)
         key                 @*key
         _                   (vswap! *key inc)
         attrs               (cond-> attrs
                               true       (dissoc :key)
-                              (== key 1) (assoc :data-reactroot "")
+                              (== key 1) (assoc  :data-reactroot "")
                               true       (assoc  :data-reactid key))
         inner-html          (:dangerouslysetinnerhtml attrs)
         attrs               (if inner-html



(defn normalize-css-key [k]
  (-> (as-str k)
      (str/replace #"[A-Z]" (fn [ch] (str "-" (str/lower-case ch))))
      (str/replace #"^ms-" "-ms-")))



(defn escape-html
  "Change special characters into HTML character entities."
  ^String [^String text]
  (.. text
    (replace "&"  "&amp;")
    (replace "<"  "&lt;")
    (replace ">"  "&gt;")
