diff --git a/Shpadoinkle-backend-snabbdom.cabal b/Shpadoinkle-backend-snabbdom.cabal
--- a/Shpadoinkle-backend-snabbdom.cabal
+++ b/Shpadoinkle-backend-snabbdom.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 9632527e5d742c734473889b8289030711690a4689627731bcd9a2f549837e4d
+-- hash: 69cf96a52080c262156727e824b26eaebddc6ac0713edcc0f367f821161c934b
 
 name:           Shpadoinkle-backend-snabbdom
-version:        0.3.0.0
+version:        0.3.0.1
 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 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
diff --git a/Shpadoinkle/Backend/Snabbdom.hs b/Shpadoinkle/Backend/Snabbdom.hs
--- a/Shpadoinkle/Backend/Snabbdom.hs
+++ b/Shpadoinkle/Backend/Snabbdom.hs
@@ -29,17 +29,23 @@
   ) where
 
 
-import           Control.Category
+import           Control.Category            ((.))
 import           Control.Monad.Base          (MonadBase (..), liftBaseDefault)
 import           Control.Monad.Catch         (MonadCatch, MonadThrow)
-import           Control.Monad.Reader
+import           Control.Monad.Reader        (MonadIO, MonadReader (..),
+                                              MonadTrans, ReaderT (..), forM_,
+                                              void, (>=>))
 import           Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
                                               MonadTransControl,
                                               defaultLiftBaseWith,
                                               defaultRestoreM)
-import           Data.FileEmbed
-import           Data.Text
-import           Data.Traversable
+import           Data.FileEmbed              (embedStringFile)
+import           Data.Text                   (Text, split)
+import           Data.Traversable            (for)
+import           GHCJS.DOM                   (currentDocumentUnchecked)
+import           GHCJS.DOM.Document          (createElement, getBodyUnsafe)
+import           GHCJS.DOM.Element           (setAttribute)
+import           GHCJS.DOM.Node              (appendChild)
 import           Language.Javascript.JSaddle hiding (JSM, MonadJSM, liftJSM,
                                               (#))
 import           Prelude                     hiding (id, (.))
@@ -134,7 +140,8 @@
       t' <- toJSVal t
       true <- toJSVal True
       case k of
-        "className" | t /= "" -> forM_ (split (== ' ') t) $ \u -> unsafeSetProp (toJSString u) true classesObj
+        "className" | t /= "" -> forM_ (split (== ' ') t) $ \u ->
+          if u == mempty then pure () else unsafeSetProp (toJSString u) true classesObj
         "style"     | t /= "" -> unsafeSetProp (toJSString k) t' attrsObj
         "type"      | t /= "" -> unsafeSetProp (toJSString k) t' attrsObj
         "autofocus" | t /= "" -> unsafeSetProp (toJSString k) t' attrsObj
@@ -211,5 +218,11 @@
 
 -- | Get the @window.container@ DOM node produced by 'setup' (@Setup.js@).
 stage :: MonadJSM m => SnabbdomT a m RawNode
-stage = liftJSM $ fromJSValUnchecked =<< jsg "container"
+stage = liftJSM $ do
+  doc <- currentDocumentUnchecked
+  elm <- createElement doc ("div" :: Text)
+  setAttribute elm ("id" :: Text) ("stage" :: Text)
+  b <- getBodyUnsafe doc
+  _ <- appendChild b elm
+  RawNode <$> toJSVal elm
 
diff --git a/Shpadoinkle/Backend/Snabbdom/Setup.js b/Shpadoinkle/Backend/Snabbdom/Setup.js
--- a/Shpadoinkle/Backend/Snabbdom/Setup.js
+++ b/Shpadoinkle/Backend/Snabbdom/Setup.js
@@ -27,9 +27,6 @@
   window.patchh = (a,b) => patch(a,b);
   window.vnode = h.default;
   window.potato = (n, e) => n.elm.appendChild(e)
-  window.container = document.createElement('div');
-  document.body.innerHTML = "";
-  document.body.appendChild(container);
   cb();
 }, 1000);
 
