                                          to-remove (difference old-thread-ids new-thread-ids)
                                          to-add (difference new-thread-ids old-thread-ids)]
                                      (vec (concat (remove (fn [t] (contains? to-remove (t :id))) old-threads)
-                                                  (filter (fn [t] (contains? to-add (t :id))) new-threads)))))))]
+                                                  (filter (fn [t] (contains? to-add (t :id))) new-threads)))))))
+        scroll-horizontally (fn [e]
+                              (let [target-classes (.. e -target -classList)]
+                                ; TODO: check if threads-div needs to scroll?
+                                (when (and (or (.contains target-classes "thread")
+                                               (.contains target-classes "threads"))
+                                        (= 0 (.-deltaX e) (.-deltaZ e)))
+                                  (set! (.-scrollLeft @this-elt)
+                                        (- (.-scrollLeft @this-elt) (.-deltaY e))))))]
     (r/create-class
       {:display-name "threads-view"
 
        :component-did-mount
        (fn [this]
-         (reset-threads! (props :threads)))
+         (reset-threads! (props :threads))
+         (reset! this-elt (r/dom-node this)))
 
        :component-will-receive-props
        (fn [this [_ next-props]]

       (fn [{:keys [new-thread-args
                    threads-opts]
             :or {threads-opts {}}}]
         [:div.threads threads-opts

          (when new-thread-args
            [new-thread-view new-thread-args])

            [braid.client.ui.views.thread :refer [thread-view]]
            [braid.client.ui.views.new-thread :refer [new-thread-view]]))

(defn threads-view
  [props]
  (let [threads (r/atom [])
        this-elt (r/atom nil)
        reset-threads! (fn [new-threads]
                         (reset! threads (vec new-threads)))
        update-threads! (fn [new-threads]
