diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -12,3 +12,15 @@
   if !impl(ghcjs)
     build-depends: ghcjs-base-stub
 ```
+
+# Changelog
+
+* 0.1.0.0
+  - Initial version with a subset of ghcjs base
+
+* 0.1.0.2
+  - Added JavaScript.Cast
+  - Added Marshall and Callbacks
+
+* 0.1.0.3
+  - Added Javascript.Web.Storage
diff --git a/ghcjs-base-stub.cabal b/ghcjs-base-stub.cabal
--- a/ghcjs-base-stub.cabal
+++ b/ghcjs-base-stub.cabal
@@ -1,5 +1,5 @@
 name:                ghcjs-base-stub
-version:             0.1.0.2
+version:             0.1.0.3
 synopsis:            Allow GHCJS projects to compile under GHC and develop using intero.
 description:         Allow GHCJS projects to compile under GHC and develop using intero.
 homepage:            https://github.com/louispan/javascript-stub#readme
@@ -12,6 +12,7 @@
 build-type:          Simple
 extra-source-files:  README.md
 cabal-version:       >=1.10
+tested-with:         GHC == 8.0.1
 
 library
   hs-source-dirs:      src
@@ -43,8 +44,10 @@
                        JavaScript.Cast
                        JavaScript.Object
                        JavaScript.Object.Internal
+                       JavaScript.Web.Storage
       build-depends:   aeson >= 0.11 && < 2
                      , attoparsec >= 0.13 && < 1
+                     , containers ==0.5.*
                      , deepseq >= 1.4 && < 2
                      , ghc-prim
                      , primitive >= 0.6 && < 1
diff --git a/src/JavaScript/Web/Storage.hs b/src/JavaScript/Web/Storage.hs
new file mode 100644
--- /dev/null
+++ b/src/JavaScript/Web/Storage.hs
@@ -0,0 +1,49 @@
+module JavaScript.Web.Storage
+    ( localStorage
+    , sessionStorage
+    , Storage
+    , getLength
+    , getIndex
+    , getItem
+    , setItem
+    , removeItem
+    , clear
+    ) where
+
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as M
+import Data.IORef (IORef, modifyIORef, newIORef, readIORef, writeIORef)
+import Data.JSString
+import System.IO.Unsafe (unsafePerformIO)
+
+newtype Storage = Storage (IORef (Map JSString JSString))
+
+localStorage :: Storage
+localStorage = Storage . unsafePerformIO $ newIORef mempty
+{-# NOINLINE localStorage #-}
+
+sessionStorage :: Storage
+sessionStorage = Storage . unsafePerformIO $ newIORef mempty
+{-# NOINLINE sessionStorage #-}
+
+getLength :: Storage -> IO Int
+getLength (Storage s) = M.size <$> readIORef s
+
+getIndex :: Int -> Storage -> IO (Maybe JSString)
+getIndex i (Storage s) = do
+    m <- readIORef s
+    if i >= 0 && i < M.size m
+        then pure $ Just $ fst $ M.elemAt i m
+        else pure Nothing
+
+getItem :: JSString -> Storage -> IO (Maybe JSString)
+getItem key (Storage s) = M.lookup key <$> readIORef s
+
+setItem :: JSString -> JSString -> Storage -> IO ()
+setItem key val (Storage s) = modifyIORef s $ M.insert key val
+
+removeItem :: JSString -> Storage -> IO ()
+removeItem key (Storage s) = modifyIORef s $ M.delete key
+
+clear :: Storage -> IO ()
+clear (Storage s) = writeIORef s mempty
