diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
 Brick changelog
 ---------------
 
+0.52
+----
+
+API changes:
+ * EventM now provides a MonadFail instance
+ * EventM now provides MonadMask, MonadCatch, and MonadThrow instances
+   (thanks Fraser Tweedale)
+
+Other changes:
+ * The FileBrowser now has support for vi-style bindings in addition to
+   its previous bindings. New bindings include:
+   * `j`/`k`: next/previous element
+   * `C-n`/`C-p`: page down/up
+   * `C-d`/`C-u`: half page down/up
+   * `g`: select first entry
+   * `G`: select last entry
+
 0.51
 ----
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.51
+version:             0.52
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal applications painlessly with 'brick'! You write an
@@ -118,6 +118,7 @@
                        data-clist >= 0.1,
                        directory >= 1.2.5.0,
                        dlist,
+                       exceptions >= 0.10.0,
                        filepath,
                        containers >= 0.5.7,
                        microlens >= 0.3.0.0,
diff --git a/programs/BorderDemo.hs b/programs/BorderDemo.hs
--- a/programs/BorderDemo.hs
+++ b/programs/BorderDemo.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
 
@@ -5,7 +6,10 @@
 import Control.Applicative ((<$>))
 #endif
 
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
+
 import qualified Data.Text as T
 import qualified Graphics.Vty as V
 
diff --git a/programs/CacheDemo.hs b/programs/CacheDemo.hs
--- a/programs/CacheDemo.hs
+++ b/programs/CacheDemo.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
 
@@ -6,7 +7,9 @@
 #endif
 
 import Control.Monad (void)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import qualified Graphics.Vty as V
 
 import qualified Brick.Types as T
diff --git a/programs/FormDemo.hs b/programs/FormDemo.hs
--- a/programs/FormDemo.hs
+++ b/programs/FormDemo.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
@@ -5,7 +6,9 @@
 import qualified Data.Text as T
 import Lens.Micro ((^.))
 import Lens.Micro.TH
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 
 import qualified Graphics.Vty as V
 import Brick
diff --git a/programs/MarkupDemo.hs b/programs/MarkupDemo.hs
--- a/programs/MarkupDemo.hs
+++ b/programs/MarkupDemo.hs
@@ -1,7 +1,10 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
 
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import qualified Graphics.Vty as V
 
 import Brick.Main (App(..), defaultMain, resizeOrQuit, neverShowCursor)
diff --git a/programs/MouseDemo.hs b/programs/MouseDemo.hs
--- a/programs/MouseDemo.hs
+++ b/programs/MouseDemo.hs
@@ -1,12 +1,17 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
 module Main where
 
+#if !MIN_VERSION_base(4,8,0)
 import Control.Applicative ((<$>))
+#endif
 import Lens.Micro ((^.), (&), (.~), (%~))
 import Lens.Micro.TH (makeLenses)
 import Control.Monad (void)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import qualified Graphics.Vty as V
 
 import qualified Brick.Types as T
@@ -125,23 +130,24 @@
 
     initialVty <- buildVty
     void $ M.customMain initialVty buildVty Nothing app $ St [] Nothing
-           "Try clicking on various UI elements.\n\
-           \Observe that the click coordinates identify the\n\
-           \underlying widget coordinates.\n\
-           \\n\
-           \Lorem ipsum dolor sit amet,\n\
-           \consectetur adipiscing elit,\n\
-           \sed do eiusmod tempor incididunt ut labore\n\
-           \et dolore magna aliqua.\n\
-           \ \n\
-           \Ut enim ad minim veniam\n\
-           \quis nostrud exercitation ullamco laboris\n\
-           \nisi ut aliquip ex ea commodo consequat.\n\
-           \\n\
-           \Duis aute irure dolor in reprehenderit\n\
-           \in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\
-           \\n\
-           \Excepteur sint occaecat cupidatat not proident,\n\
-           \sunt in culpa qui officia deserunt mollit\n\
-           \anim id est laborum.\n"
+           (unlines [ "Try clicking on various UI elements."
+                    , "Observe that the click coordinates identify the"
+                    , "underlying widget coordinates."
+                    , ""
+                    , "Lorem ipsum dolor sit amet,"
+                    , "consectetur adipiscing elit,"
+                    , "sed do eiusmod tempor incididunt ut labore"
+                    , "et dolore magna aliqua."
+                    , ""
+                    , "Ut enim ad minim veniam"
+                    , "quis nostrud exercitation ullamco laboris"
+                    , "isi ut aliquip ex ea commodo consequat."
+                    , ""
+                    , "Duis aute irure dolor in reprehenderit"
+                    , "in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
+                    , ""
+                    , "Excepteur sint occaecat cupidatat not proident,"
+                    , "sunt in culpa qui officia deserunt mollit"
+                    , "anim id est laborum."
+                    ])
            (E.editor TextBox Nothing "")
diff --git a/programs/TextWrapDemo.hs b/programs/TextWrapDemo.hs
--- a/programs/TextWrapDemo.hs
+++ b/programs/TextWrapDemo.hs
@@ -1,6 +1,9 @@
+{-# LANGUAGE CPP #-}
 module Main where
 
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import Brick
 import Text.Wrap (defaultWrapSettings, preserveIndentation)
 
diff --git a/programs/ViewportScrollDemo.hs b/programs/ViewportScrollDemo.hs
--- a/programs/ViewportScrollDemo.hs
+++ b/programs/ViewportScrollDemo.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
 
@@ -6,7 +7,9 @@
 #endif
 
 import Control.Monad (void)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import qualified Graphics.Vty as V
 
 import qualified Brick.Types as T
diff --git a/src/Brick/Forms.hs b/src/Brick/Forms.hs
--- a/src/Brick/Forms.hs
+++ b/src/Brick/Forms.hs
@@ -5,7 +5,11 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 -- | NOTE: This API is experimental and will probably change. Please try
 -- it out! Feedback is very much appreciated, and your patience in the
--- face of breaking API changes is also appreciated!
+-- face of breaking API changes is also appreciated! It's also worth
+-- bearing in mind that this API is designed to support a narrow range
+-- of use cases. If you find that you need more customization than this
+-- offers, then you will need to consider building your own layout and
+-- event handling for input fields.
 --
 -- For a fuller introduction to this API, see the "Input Forms" section
 -- of the Brick User Guide. Also see the demonstration programs for
@@ -19,10 +23,6 @@
 -- user when a form field's value is invalid, and stores valid inputs in
 -- your data type when possible.
 --
--- This module provides the API to create forms, populate them with some
--- basic input field types, render forms, handle form events, and create
--- custom input field types.
---
 -- A form has both a visual representation and a corresponding data
 -- structure representing the latest valid values for that form
 -- (referred to as the "state" of the form). A 'FormField' is a single
@@ -91,7 +91,6 @@
 
 import Brick
 import Brick.Focus
-import Brick.Widgets.Core (showCursor)
 import Brick.Widgets.Edit
 import Brick.Widgets.List
 import qualified Data.Text.Zipper as Z
@@ -113,9 +112,9 @@
 --  * @e@ - your application's event type
 --  * @n@ - your application's resource name type
 data FormField a b e n =
-    FormField { formFieldName        :: n
+    FormField { formFieldName :: n
               -- ^ The name identifying this form field.
-              , formFieldValidate    :: b -> Maybe a
+              , formFieldValidate :: b -> Maybe a
               -- ^ A validation function converting this field's state
               -- into a value of your choosing. @Nothing@ indicates a
               -- validation failure. For example, this might validate
@@ -131,7 +130,7 @@
               -- can be set with 'setFieldValid'. The value of this
               -- field also affects the behavior of 'allFieldsValid' and
               -- 'getInvalidFields'.
-              , formFieldRender      :: Bool -> b -> Widget n
+              , formFieldRender :: Bool -> b -> Widget n
               -- ^ A function to render this form field. Parameters are
               -- whether the field is currently focused, followed by the
               -- field state.
@@ -166,11 +165,11 @@
                       -- the field collection. Note that this type is
                       -- existential. All form fields in the collection
                       -- must validate to this type.
-                      , formFieldLens  :: Lens' s a
+                      , formFieldLens :: Lens' s a
                       -- ^ A lens to extract and store a
                       -- successfully-validated form input back into
                       -- your form state.
-                      , formFields     :: [FormField a b e n]
+                      , formFields :: [FormField a b e n]
                       -- ^ The form fields, in order, that the user will
                       -- interact with to manipulate this state value.
                       , formFieldRenderHelper :: Widget n -> Widget n
@@ -195,10 +194,10 @@
 --  * @n@ - your application's resource name type
 data Form s e n =
     Form { formFieldStates  :: [FormFieldState s e n]
-         , formFocus        :: FocusRing n
+         , formFocus :: FocusRing n
          -- ^ The focus ring for the form, indicating which form field
          -- has input focus.
-         , formState        :: s
+         , formState :: s
          -- ^ The current state of the form. Forms guarantee that only
          -- valid inputs ever get stored in the state, and that after
          -- each input event on a form field, if that field contains a
@@ -306,14 +305,14 @@
         handleEvent (VtyEvent (EvKey (KChar ' ') [])) s = return $ not s
         handleEvent _ s = return s
 
-    in FormFieldState { formFieldState        = initVal
-                      , formFields            = [ FormField name Just True
-                                                            (renderCheckbox lb check rb label name)
-                                                            handleEvent
-                                                ]
-                      , formFieldLens         = stLens
+    in FormFieldState { formFieldState = initVal
+                      , formFields = [ FormField name Just True
+                                                 (renderCheckbox lb check rb label name)
+                                                 handleEvent
+                                     ]
+                      , formFieldLens = stLens
                       , formFieldRenderHelper = id
-                      , formFieldConcat       = vBox
+                      , formFieldConcat = vBox
                       }
 
 renderCheckbox :: Char -> Char -> Char -> T.Text -> n -> Bool -> Bool -> Widget n
@@ -360,14 +359,14 @@
         handleEvent (VtyEvent e) s = handleListEvent e s
         handleEvent _ s = return s
 
-    in FormFieldState { formFieldState        = initVal
-                      , formFields            = [ FormField name Just True
-                                                            (renderList renderItem)
-                                                            handleEvent
-                                                ]
-                      , formFieldLens         = customStLens
+    in FormFieldState { formFieldState = initVal
+                      , formFields = [ FormField name Just True
+                                                 (renderList renderItem)
+                                                 handleEvent
+                                     ]
+                      , formFieldLens = customStLens
                       , formFieldRenderHelper = id
-                      , formFieldConcat       = vBox
+                      , formFieldConcat = vBox
                       }
 -- | A form field for selecting a single choice from a set of possible
 -- choices. Each choice has an associated value and text label.
@@ -393,8 +392,11 @@
 -- option and to mouse clicks.
 radioCustomField :: (Ord n, Show n, Eq a)
                  => Char
+                 -- ^ Left bracket character.
                  -> Char
+                 -- ^ Checkmark character.
                  -> Char
+                 -- ^ Right bracket character.
                  -> Lens' s a
                  -- ^ The state lens for this value.
                  -> [(a, n, T.Text)]
@@ -427,11 +429,11 @@
                       (renderRadio lb check rb val name label)
                       (handleEvent val)
 
-    in FormFieldState { formFieldState        = initVal
-                      , formFields            = optionFields
-                      , formFieldLens         = stLens
+    in FormFieldState { formFieldState = initVal
+                      , formFields = optionFields
+                      , formFieldLens = stLens
                       , formFieldRenderHelper = id
-                      , formFieldConcat       = vBox
+                      , formFieldConcat = vBox
                       }
 
 renderRadio :: (Eq a) => Char -> Char -> Char -> a -> n -> T.Text -> Bool -> a -> Widget n
@@ -490,13 +492,13 @@
         handleEvent _ ed = return ed
 
     in FormFieldState { formFieldState = initVal
-                      , formFields     = [ FormField n
-                                                     (val . getEditContents)
-                                                     True
-                                                     (\b e -> wrapEditor $ renderEditor renderText b e)
-                                                     handleEvent
-                                         ]
-                      , formFieldLens  = stLens
+                      , formFields = [ FormField n
+                                                 (val . getEditContents)
+                                                 True
+                                                 (\b e -> wrapEditor $ renderEditor renderText b e)
+                                                 handleEvent
+                                     ]
+                      , formFieldLens = stLens
                       , formFieldRenderHelper = id
                       , formFieldConcat = vBox
                       }
diff --git a/src/Brick/Themes.hs b/src/Brick/Themes.hs
--- a/src/Brick/Themes.hs
+++ b/src/Brick/Themes.hs
@@ -89,7 +89,9 @@
 import Data.List (intercalate)
 import Data.Bits ((.|.), (.&.))
 import Data.Maybe (fromMaybe, isNothing, catMaybes, mapMaybe)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import qualified Data.Foldable as F
 
 import Data.Ini.Config
diff --git a/src/Brick/Types.hs b/src/Brick/Types.hs
--- a/src/Brick/Types.hs
+++ b/src/Brick/Types.hs
@@ -88,6 +88,10 @@
 
 import Lens.Micro (_1, _2, to, (^.), (&), (.~), Lens')
 import Lens.Micro.Type (Getting)
+import Control.Monad.Catch (MonadThrow, MonadCatch, MonadMask)
+#if !MIN_VERSION_base(4,13,0)
+import Control.Monad.Fail (MonadFail)
+#endif
 import Control.Monad.Trans.State.Lazy
 import Control.Monad.Trans.Reader
 import Graphics.Vty (Attr)
@@ -128,7 +132,9 @@
 newtype EventM n a =
     EventM { runEventM :: ReaderT (EventRO n) (StateT (EventState n) IO) a
            }
-           deriving (Functor, Applicative, Monad, MonadIO)
+           deriving ( Functor, Applicative, Monad, MonadIO
+                    , MonadThrow, MonadCatch, MonadMask, MonadFail
+                    )
 
 -- | Widget size policies. These policies communicate how a widget uses
 -- space when being rendered. These policies influence rendering order
diff --git a/src/Brick/Util.hs b/src/Brick/Util.hs
--- a/src/Brick/Util.hs
+++ b/src/Brick/Util.hs
@@ -9,7 +9,9 @@
 where
 
 import Lens.Micro ((&), (%~))
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
+#endif
 import Graphics.Vty
 
 import Brick.Types.Internal (Location(..), CursorLocation(..), cursorLocationL)
diff --git a/src/Brick/Widgets/Core.hs b/src/Brick/Widgets/Core.hs
--- a/src/Brick/Widgets/Core.hs
+++ b/src/Brick/Widgets/Core.hs
@@ -91,9 +91,11 @@
   )
 where
 
-#if MIN_VERSION_base(4,8,0)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid ((<>))
-#else
+#endif
+
+#if !MIN_VERSION_base(4,8,0)
 import Control.Applicative
 import Data.Monoid ((<>), mempty)
 #endif
diff --git a/src/Brick/Widgets/FileBrowser.hs b/src/Brick/Widgets/FileBrowser.hs
--- a/src/Brick/Widgets/FileBrowser.hs
+++ b/src/Brick/Widgets/FileBrowser.hs
@@ -53,6 +53,7 @@
   , FileInfo(..)
   , FileStatus(..)
   , FileType(..)
+
   -- * Making a new file browser
   , newFileBrowser
   , selectNonDirectories
@@ -598,6 +599,31 @@
 handleFileBrowserEventCommon :: (Ord n) => Vty.Event -> FileBrowser n -> EventM n (FileBrowser n)
 handleFileBrowserEventCommon e b =
     case e of
+        Vty.EvKey (Vty.KChar 'b') [Vty.MCtrl] -> do
+            let old = b ^. fileBrowserEntriesL
+            new <- listMovePageUp old
+            return $ b & fileBrowserEntriesL .~ new
+        Vty.EvKey (Vty.KChar 'f') [Vty.MCtrl] -> do
+            let old = b ^. fileBrowserEntriesL
+            new <- listMovePageDown old
+            return $ b & fileBrowserEntriesL .~ new
+        Vty.EvKey (Vty.KChar 'd') [Vty.MCtrl] -> do
+            let old = b ^. fileBrowserEntriesL
+            new <- listMoveByPages (0.5::Double) old
+            return $ b & fileBrowserEntriesL .~ new
+        Vty.EvKey (Vty.KChar 'u') [Vty.MCtrl] -> do
+            let old = b ^. fileBrowserEntriesL
+            new <- listMoveByPages (-0.5::Double) old
+            return $ b & fileBrowserEntriesL .~ new
+        Vty.EvKey (Vty.KChar 'g') [] ->
+            return $ b & fileBrowserEntriesL %~ listMoveTo 0
+        Vty.EvKey (Vty.KChar 'G') [] -> do
+            let sz = length (listElements $ b^.fileBrowserEntriesL)
+            return $ b & fileBrowserEntriesL %~ listMoveTo (sz - 1)
+        Vty.EvKey (Vty.KChar 'j') [] ->
+            return $ b & fileBrowserEntriesL %~ listMoveBy 1
+        Vty.EvKey (Vty.KChar 'k') [] ->
+            return $ b & fileBrowserEntriesL %~ listMoveBy (-1)
         Vty.EvKey (Vty.KChar 'n') [Vty.MCtrl] ->
             return $ b & fileBrowserEntriesL %~ listMoveBy 1
         Vty.EvKey (Vty.KChar 'p') [Vty.MCtrl] ->
diff --git a/src/Brick/Widgets/Internal.hs b/src/Brick/Widgets/Internal.hs
--- a/src/Brick/Widgets/Internal.hs
+++ b/src/Brick/Widgets/Internal.hs
@@ -21,7 +21,7 @@
 import Brick.Types.Internal
 import Brick.AttrMap
 import Brick.Widgets.Border.Style
-import Brick.BorderMap (BorderMap, Edges(..))
+import Brick.BorderMap (BorderMap)
 import qualified Brick.BorderMap as BM
 
 renderFinal :: AttrMap
diff --git a/src/Brick/Widgets/List.hs b/src/Brick/Widgets/List.hs
--- a/src/Brick/Widgets/List.hs
+++ b/src/Brick/Widgets/List.hs
@@ -461,9 +461,9 @@
 listMoveUp = listMoveBy (-1)
 
 -- | Move the list selected index up by one page.
-listMovePageUp
-  :: (Foldable t, Splittable t, Ord n)
-  => GenericList n t e -> EventM n (GenericList n t e)
+listMovePageUp :: (Foldable t, Splittable t, Ord n)
+               => GenericList n t e
+               -> EventM n (GenericList n t e)
 listMovePageUp = listMoveByPages (-1::Double)
 
 -- | Move the list selected index down by one. (Moves the cursor down,
