diff --git a/examples/mario/Main.hs b/examples/mario/Main.hs
--- a/examples/mario/Main.hs
+++ b/examples/mario/Main.hs
@@ -25,13 +25,16 @@
 main = do
     time <- now
     let m = mario { time = time }
-    startApp App { model = m, initialAction = NoOp, ..}
+    startApp App { model = m
+                 , initialAction = NoOp
+                 , ..
+                 }
   where
     update = updateMario
     view   = display
     events = defaultEvents
     subs   = [ arrowsSub GetArrows
-             , windowSub WindowCoords
+             , windowCoordsSub WindowCoords
              ]
     mountPoint = Nothing
 
diff --git a/ghcjs-src/Miso.hs b/ghcjs-src/Miso.hs
--- a/ghcjs-src/Miso.hs
+++ b/ghcjs-src/Miso.hs
@@ -87,10 +87,12 @@
                                             (Acc oldModel (pure ())) actions
         effects
         when (oldModel /= newModel) $ do
+          swapCallbacks
           newVTree <- runView (view newModel) writeEvent
           oldVTree <- readIORef viewRef
           void $ waitForAnimationFrame
           (diff mountPoint) (Just oldVTree) (Just newVTree)
+          releaseCallbacks
           atomicWriteIORef viewRef newVTree
         loop newModel
   loop m
@@ -137,3 +139,11 @@
 -- entry point into isomorphic javascript
 foreign import javascript unsafe "copyDOMIntoVTree($1);"
   copyDOMIntoVTree :: JSVal -> IO ()
+
+-- | Pins down the current callbacks for clearing later
+foreign import javascript unsafe "swapCallbacks();"
+  swapCallbacks :: IO ()
+
+-- | Releases callbacks registered by the virtual DOM.
+foreign import javascript unsafe "releaseCallbacks();"
+  releaseCallbacks :: IO ()
diff --git a/ghcjs-src/Miso/FFI.hs b/ghcjs-src/Miso/FFI.hs
--- a/ghcjs-src/Miso/FFI.hs
+++ b/ghcjs-src/Miso/FFI.hs
@@ -16,6 +16,8 @@
    , windowRemoveEventListener
    , windowInnerHeight
    , windowInnerWidth
+   , eventPreventDefault
+   , eventStopPropagation
    , now
    , consoleLog
    , stringify
@@ -23,6 +25,8 @@
    , item
    , jsvalToValue
    , clearBody
+   , objectToJSON
+   , getWindow
    ) where
 
 import           Control.Monad
@@ -79,6 +83,19 @@
 foreign import javascript unsafe "window.removeEventListener($1, $2);"
   windowRemoveEventListener :: JSString -> Callback (JSVal -> IO ()) -> IO ()
 
+
+foreign import javascript unsafe "$1.stopPropagation();"
+    eventStopPropagation :: JSVal -> IO ()
+
+foreign import javascript unsafe "$1.preventDefault();"
+    eventPreventDefault :: JSVal -> IO ()
+
+
+-- | Window object
+foreign import javascript unsafe "$r = window;"
+  getWindow :: IO JSVal
+
+
 -- | Retrieves inner height
 foreign import javascript unsafe "$r = window.innerHeight;"
   windowInnerHeight :: IO Int
@@ -125,3 +142,10 @@
 -- creating multiple copies of your app when running in GHCJSi.
 foreign import javascript unsafe "document.body.innerHTML = '';"
   clearBody :: IO ()
+
+
+foreign import javascript unsafe "$r = objectToJSON($1,$2);"
+  objectToJSON
+    :: JSVal -- ^ decodeAt :: [JSString]
+    -> JSVal -- ^ object with impure references to the DOM
+    -> IO JSVal
diff --git a/ghcjs-src/Miso/Html/Internal.hs b/ghcjs-src/Miso/Html/Internal.hs
--- a/ghcjs-src/Miso/Html/Internal.hs
+++ b/ghcjs-src/Miso/Html/Internal.hs
@@ -223,12 +223,6 @@
    -> Attribute action
 on = onWithOptions defaultOptions
 
-foreign import javascript unsafe "$r = objectToJSON($1,$2);"
-  objectToJSON
-    :: JSVal -- ^ decodeAt :: [JSString]
-    -> JSVal -- ^ object with impure references to the DOM
-    -> IO JSVal
-
 -- | @onWithOptions opts eventName decoder toAction@ is an attribute
 -- that will set the event handler of the associated DOM node to a function that
 -- decodes its argument using @decoder@, converts it to an action
@@ -251,12 +245,13 @@
    eventHandlerObject@(Object eo) <- create
    jsOptions <- toJSVal options
    decodeAtVal <- toJSVal decodeAt
-   cb <- jsval <$> (asyncCallback1 $ \e -> do
+   cb <- asyncCallback1 $ \e -> do
        Just v <- jsvalToValue =<< objectToJSON decodeAtVal e
        case parseEither decoder v of
          Left s -> error $ "Parse error on " <> unpack eventName <> ": " <> s
-         Right r -> sink (toAction r))
-   setProp "runEvent" cb eventHandlerObject
+         Right r -> sink (toAction r)
+   setProp "runEvent" (jsval cb) eventHandlerObject
+   registerCallback cb
    setProp "options" jsOptions eventHandlerObject
    setProp eventName eo (Object eventObj)
 
@@ -265,8 +260,9 @@
 onCreated :: action -> Attribute action
 onCreated action =
   Attribute $ \sink n -> do
-    cb <- jsval <$> asyncCallback (sink action)
-    setProp "onCreated" cb n
+    cb <- asyncCallback (sink action)
+    setProp "onCreated" (jsval cb) n
+    registerCallback cb
 
 -- | @onDestroyed action@ is an event that gets called after the DOM element
 -- is removed from the DOM. The @action@ is given the DOM element that was
@@ -274,8 +270,9 @@
 onDestroyed :: action -> Attribute action
 onDestroyed action =
   Attribute $ \sink n -> do
-    cb <- jsval <$> asyncCallback (sink action)
-    setProp "onDestroyed" cb n
+    cb <- asyncCallback (sink action)
+    setProp "onDestroyed" (jsval cb) n
+    registerCallback cb
 
 -- | @style_ attrs@ is an attribute that will set the @style@
 -- attribute of the associated DOM node to @attrs@.
@@ -292,3 +289,8 @@
    cssObj <- getProp "css" n
    forM_ (M.toList m) $ \(k,v) ->
      setProp k (jsval v) (Object cssObj)
+
+foreign import javascript unsafe "registerCallback($1);"
+  registerCallback
+    :: Callback a
+    -> IO ()
diff --git a/ghcjs-src/Miso/Subscription/History.hs b/ghcjs-src/Miso/Subscription/History.hs
--- a/ghcjs-src/Miso/Subscription/History.hs
+++ b/ghcjs-src/Miso/Subscription/History.hs
@@ -49,18 +49,21 @@
 -- | Pushes a new URI onto the History stack
 pushURI :: URI -> IO ()
 {-# INLINE pushURI #-}
-pushURI uri = pushStateNoModel uri { uriPath = path }
-  where
-    path | uriPath uri == mempty = "/"
-         | otherwise = uriPath uri
+pushURI uri = pushStateNoModel uri { uriPath = toPath uri }
 
+-- | Prepend '/' if necessary
+toPath :: URI -> String
+toPath uri =
+  case uriPath uri of
+    "" -> "/"
+    "/" -> "/"
+    xs@('/' : _) -> xs
+    xs -> '/' : xs
+
 -- | Replaces current URI on stack
 replaceURI :: URI -> IO ()
 {-# INLINE replaceURI #-}
-replaceURI uri = replaceTo' uri { uriPath = path }
-  where
-    path | uriPath uri == mempty = "/"
-         | otherwise = uriPath uri
+replaceURI uri = replaceTo' uri { uriPath = toPath uri }
 
 -- | Navigates backwards
 back :: IO ()
diff --git a/ghcjs-src/Miso/Subscription/Window.hs b/ghcjs-src/Miso/Subscription/Window.hs
--- a/ghcjs-src/Miso/Subscription/Window.hs
+++ b/ghcjs-src/Miso/Subscription/Window.hs
@@ -11,18 +11,28 @@
 ----------------------------------------------------------------------------
 module Miso.Subscription.Window where
 
+import Control.Monad
+import Data.Monoid
+
 import GHCJS.Foreign.Callback
 import GHCJS.Marshal
-
 import JavaScript.Object
 import JavaScript.Object.Internal
+
+import Miso.Event
 import Miso.FFI
-import Miso.Html.Internal ( Sub )
+import Miso.Html.Internal         ( Sub )
+import Miso.String
 
+import Miso.String
+import Miso.Event
+
+import Data.Aeson.Types (parseEither)
+
 -- | Captures window coordinates changes as they occur and writes them to
 -- an event sink
-windowSub :: ((Int, Int) -> action) -> Sub action
-windowSub f = \sink -> do
+windowCoordsSub :: ((Int, Int) -> action) -> Sub action
+windowCoordsSub f = \sink -> do
   sink . f =<< (,) <$> windowInnerHeight <*> windowInnerWidth
   windowAddEventListener "resize" =<< do
     asyncCallback1 $ \windowEvent -> do
@@ -30,3 +40,21 @@
       Just w <- fromJSVal =<< getProp "innerWidth" (Object target)
       Just h <- fromJSVal =<< getProp "innerHeight" (Object target)
       sink $ f (h, w)
+
+-- | @windowOn eventName decoder toAction@ is a subscription which parallels the
+-- attribute handler `on`, providing a subscription to listen to window level events.
+windowSub :: MisoString -> Decoder r -> (r -> action) -> Sub action
+windowSub  = windowSubWithOptions defaultOptions
+
+windowSubWithOptions :: Options -> MisoString -> Decoder r -> (r -> action) -> Sub action
+windowSubWithOptions Options{..} eventName Decoder{..} toAction = \sink -> do
+  windowAddEventListener eventName =<< do
+    decodeAtVal <- toJSVal decodeAt
+    asyncCallback1 $ \e -> do
+      Just v <- jsvalToValue =<< objectToJSON decodeAtVal e
+      case parseEither decoder v of
+        Left s -> error $ "Parse error on " <> unpack eventName <> ": " <> s
+        Right r -> do
+          when stopPropagation $ eventStopPropagation e
+          when preventDefault $ eventPreventDefault e
+          sink (toAction r)
diff --git a/ghcjs-src/Miso/Types.hs b/ghcjs-src/Miso/Types.hs
--- a/ghcjs-src/Miso/Types.hs
+++ b/ghcjs-src/Miso/Types.hs
@@ -9,6 +9,8 @@
 ----------------------------------------------------------------------------
 module Miso.Types
   ( App (..)
+  , Effect
+  , Sub
 
     -- * The Transition Monad
   , Transition
diff --git a/jsbits/delegate.js b/jsbits/delegate.js
--- a/jsbits/delegate.js
+++ b/jsbits/delegate.js
@@ -1,3 +1,29 @@
+var oldCallbacks = [];
+var currentCallbacks = [];
+
+/* Callbacks in ghcjs need to be released. With this function one can register
+   callbacks that should be released right before diffing.
+*/
+function registerCallback(cb) {
+    currentCallbacks.push(cb);
+}
+
+/* Swaps out the new calbacks for old callbacks.
+The old callbacks should be cleared once the new callbacks have replaced them.
+*/
+function swapCallbacks() {
+  oldCallbacks = currentCallbacks;
+  currentCallbacks = [];
+}
+
+/* This releases the old callbacks. */
+function releaseCallbacks() {
+    for (var i in oldCallbacks)
+      h$release(oldCallbacks[i]);
+
+    oldCallbacks = [];
+}
+
 /* event delegation algorithm */
 function delegate(mountPointElement, events, getVTree) {
     for (var event in events) {
diff --git a/jsbits/diff.js b/jsbits/diff.js
--- a/jsbits/diff.js
+++ b/jsbits/diff.js
@@ -172,7 +172,7 @@
 	newFirstIndex = 0,
 	oldLastIndex = os.length - 1,
 	newLastIndex = ns.length - 1,
-	nFirst, nLast, tmp, found, node;
+	nFirst, nLast, oLast, oFirst, tmp, found, node;
     for (;;) {
 	/* check base case, first > last for both new and old
 	  [ ] -- old children empty (fully-swapped)
diff --git a/miso.cabal b/miso.cabal
--- a/miso.cabal
+++ b/miso.cabal
@@ -1,5 +1,5 @@
 name:                miso
-version:             0.17.0.0
+version:             0.18.0.0
 category:            Web, Miso, Data Structures
 license:             BSD3
 license-file:        LICENSE
