diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,26 +1,27 @@
-Shpadoinkle Snabbdom, I think I know exactly what it means
-Copyright © 2020 Isaac Shpaira
+Shpadoinkle Snabbdom aka S11 Snabbdom
+Copyright © 2020 Isaac Shapira
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-3. Neither the name of the <`3:organization`> nor the
-names of its contributors may be used to endorse or promote products
-derived from this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY <|2|> ''AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL <|2|> BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+ * Neither the name of Shpadoinkle nor the names of its contributors may be
+   used to endorse or promote products derived from this software without
+   specific prior written permission.
 
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 # Shpadoinkle Backend Snabbdom
 
 [![Goldwater](https://gitlab.com/fresheyeball/Shpadoinkle/badges/master/pipeline.svg)](https://gitlab.com/fresheyeball/Shpadoinkle)
+[![Haddock](https://img.shields.io/badge/haddock-master-informational)](https://shpadoinkle.org/backend-snabbdom)
 [![BSD-3](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
 [![built with nix](https://img.shields.io/badge/built%20with-nix-41439a)](https://builtwithnix.org)
 [![Hackage](https://img.shields.io/hackage/v/Shpadoinkle-backend-snabbdom.svg)](https://hackage.haskell.org/package/Shpadoinkle-backend-snabbdom)
@@ -11,8 +12,7 @@
 
 > Snabbdom consists of an extremely simple, performant, and extensible core that is only ≈ 200 SLOC. It offers a modular architecture with rich functionality for extensions through custom modules. To keep the core simple, all non-essential functionality is delegated to modules.
 
-These design decisions made Snabbdom a good fit for Shpadoinkle's first high-performance pure JavaScript backend. Right now Snabbdom is being provided via [CloudFlare](https://cdnjs.com/) content delivery network (CDN) and is not included in this repo. This is great for getting started fast and having a transparent developer experience where you can simply switch to the backend of your choosing. However, this is not a stable long term approach as the CDN artifact could be removed at any time. If you wish to use Snabbdom in production, I recommend either:
+These design decisions made Snabbdom a good fit for Shpadoinkle's first high-performance pure JavaScript backend. Right now Snabbdom is being provided using [CloudFlare](https://cdnjs.com/) content delivery network (CDN) and is not included in this repo. This is great for getting started fast and having a transparent developer experience where you can simply switch to the backend of your choosing. However, this is not a stable long term approach as the CDN artifact could be removed at any time. If you wish to use Snabbdom in production, I recommend either:
 
 - Proactively monitoring the CDN endpoints
 - Wrap `SnabbdomT` in your own `newtype` and overriding the `setup` method in the `Backend` instance with a mechanism where you provide Snabbdom's JavaScript artifacts yourself.
-
diff --git a/Shpadoinkle-backend-snabbdom.cabal b/Shpadoinkle-backend-snabbdom.cabal
--- a/Shpadoinkle-backend-snabbdom.cabal
+++ b/Shpadoinkle-backend-snabbdom.cabal
@@ -4,12 +4,12 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 8d640457d8dcfbf7edf0ce733ba9d6c10d9beb6d8c62b7bbd10c0a294a0f2cb7
+-- hash: 6ac6720a8444015edf2b03ef30437c3c9ec703c559e4c205e6e1145bca8bdf91
 
 name:           Shpadoinkle-backend-snabbdom
-version:        0.1.0.1
+version:        0.2.0.0
 synopsis:       Use the high-performance Snabbdom virtual dom library written in JavaScript.
-description:    Snabbdom is a battle-tested virtual dom library for JavaScript. It's extremely fast, lean, and modular. Snabbdom's design made it a natural choice for a Shpadoinkle rendering backend, as it has a similar core philosophy of "just don't do much" and is friendly to purely functional binding.
+description:    Snabbdom is a battle-tested virtual DOM library for JavaScript. It's extremely fast, lean, and modular. Snabbdom's design makes Snabbdom a natural choice for a Shpadoinkle rendering backend, as it has a similar core philosophy of "just don't do much" and is friendly to purely functional binding.
 category:       Web
 author:         Isaac Shapira
 maintainer:     fresheyeball@protonmail.com
@@ -37,7 +37,9 @@
       Shpadoinkle
     , base >=4.12.0 && <4.16
     , file-embed >=0.0.11 && <0.1
+    , ghcjs-dom >=0.9.4 && <0.20
     , jsaddle >=0.9.7 && <0.20
     , mtl >=2.2.2 && <2.3
     , text >=1.2.3 && <1.3
+    , unliftio >=0.2.12 && <0.3
   default-language: Haskell2010
diff --git a/Shpadoinkle/Backend/Snabbdom.hs b/Shpadoinkle/Backend/Snabbdom.hs
--- a/Shpadoinkle/Backend/Snabbdom.hs
+++ b/Shpadoinkle/Backend/Snabbdom.hs
@@ -9,26 +9,34 @@
 {-# LANGUAGE RankNTypes                 #-}
 {-# LANGUAGE StandaloneDeriving         #-}
 {-# LANGUAGE TemplateHaskell            #-}
+{-# LANGUAGE TupleSections              #-}
 {-# LANGUAGE TypeApplications           #-}
 {-# LANGUAGE TypeFamilies               #-}
 {-# LANGUAGE TypeOperators              #-}
 {-# OPTIONS_GHC -fno-warn-type-defaults #-}
 
 
+{-|
+   This module provides the 'Backend' binding for the JavaScript virtual DOM implementation <https://github.com/snabbdom/snabbdom Snabbdom>.
+-}
+
+
 module Shpadoinkle.Backend.Snabbdom
   ( SnabbdomT (..)
   , runSnabbdom
   , stage
   ) where
 
+
 import           Control.Category
 import           Control.Monad.Reader
 import           Data.FileEmbed
 import           Data.Text
 import           Data.Traversable
-import           GHC.Conc
-import           Language.Javascript.JSaddle hiding (( # ))
-import           Prelude                     hiding ((.))
+import           GHCJS.DOM.Types             (JSM, MonadJSM, liftJSM)
+import           Language.Javascript.JSaddle hiding (( # ), JSM, MonadJSM, liftJSM)
+import           Prelude                     hiding (id, (.))
+import           UnliftIO.STM                (TVar)
 
 import           Shpadoinkle                 hiding (children, name, props)
 
@@ -50,11 +58,12 @@
 #endif
 
 
+-- | 'SnabbdomT' is a @newtype@ of 'ReaderT', this is the 'runReaderT' equivalent.
 runSnabbdom :: TVar model -> SnabbdomT model m a -> m a
 runSnabbdom t (Snabbdom r) = runReaderT r t
 
 
-props :: (m ~> JSM) -> TVar a -> [(Text, Prop (SnabbdomT a m) a)] -> JSM Object
+props :: Monad m => (m ~> JSM) -> TVar a -> [(Text, Prop (SnabbdomT a m) a)] -> JSM Object
 props toJSM i xs = do
   o <- create
   a <- create
@@ -65,14 +74,15 @@
       t' <- toJSVal t
       true <- toJSVal True
       case k of
-        "className" | t /= "" -> unsafeSetProp (toJSString t) true c
+        "className" | t /= "" -> forM_ (split (== ' ') t) $ \u -> unsafeSetProp (toJSString u) true c
         _                     -> unsafeSetProp (toJSString k) t' a
     PListener f -> do
       f' <- toJSVal . fun $ \_ _ -> \case
         [] -> return ()
         ev:_ -> do
           rn <- unsafeGetProp "target" =<< valToObject ev
-          liftIO . atomically . writeTVar i =<< (toJSM . runSnabbdom i) (f (RawNode rn) (RawEvent ev))
+          x <- f (RawNode rn) (RawEvent ev)
+          writeUpdate i $ hoist (toJSM . runSnabbdom i) x
       unsafeSetProp (toJSString k) f' e
     PFlag b -> do
       f <- toJSVal b
@@ -124,12 +134,13 @@
     where f' = maybe r unVNode f
 
 
-  setup :: JSM () -> SnabbdomT a m ()
-  setup cb = liftJSM $ do
+  setup :: JSM () -> JSM ()
+  setup cb = do
     void $ eval @Text $(embedStringFile "Shpadoinkle/Backend/Snabbdom/Setup.js")
     void . jsg1 "startApp" . fun $ \_ _ _ -> cb
 
 
+-- | Get the @window.container@ DOM node produced by 'setup' (@Setup.js@).
 stage :: MonadJSM m => SnabbdomT a m RawNode
 stage = liftJSM $ fromJSValUnchecked =<< jsg "container"
 
