diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
 Brick changelog
 ---------------
 
+0.35
+----
+
+ * Added support for GHC 8.4.
+ * Updated travis build to test on all 8.x releases (thanks Peter
+   Simons)
+
 0.34.1
 ------
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -128,11 +128,12 @@
 performance later for the sake of spending more time on the design
 (and to wait on performance issues to arise first). `brick` is also
 something of an experimental project of mine and some aspects of the
-design involve trade-offs that are not entirely settled. In addition you
-can expect this library to follow a principle of fearless improvement:
-new versions will make (sometimes substantial) API changes if those
-changes really do make the library better. I will place more importance
-on getting the API right than on maintaining backwards compatibility.
+design involve trade-offs that might not be right for your application.
+Brick is not intended to be all things to all people; rather, I want it
+to provide a good foundation for building complex terminal interfaces
+in a declarative style to take away specific headaches of building,
+modifying, and working with such interfaces, all while seeing how far we
+can get with a pure function to specify the interface.
 
 `brick` exports an extension API that makes it possible to make your own
 packages and widgets. If you use that, you'll also be helping to test
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.34.1
+version:             0.35
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal applications painlessly with 'brick'! You write an
@@ -37,6 +37,7 @@
 cabal-version:       >=1.18
 Homepage:            https://github.com/jtdaugherty/brick/
 Bug-reports:         https://github.com/jtdaugherty/brick/issues
+tested-with:         GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1
 
 extra-doc-files:     README.md,
                      docs/guide.rst,
@@ -82,7 +83,7 @@
     Brick.Types.Internal
     Brick.Widgets.Internal
 
-  build-depends:       base <= 5,
+  build-depends:       base <= 4.11.0.0,
                        vty >= 5.18.1,
                        transformers,
                        data-clist >= 0.1,
@@ -191,7 +192,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             DialogDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -204,7 +205,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             MouseDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -219,7 +220,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             LayerDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -233,7 +234,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             SuspendAndResumeDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -247,7 +248,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             PaddingDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -260,7 +261,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             ThemeDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -273,7 +274,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             AttrDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -286,7 +287,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             MarkupDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -299,7 +300,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             ListDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -313,7 +314,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             ListViDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -327,7 +328,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             CustomEventDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -341,7 +342,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             FillDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -354,7 +355,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             HelloWorldDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -367,7 +368,7 @@
   ghc-options:         -threaded -Wall -fno-warn-unused-do-bind -O3
   default-language:    Haskell2010
   main-is:             EditDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -383,7 +384,7 @@
   default-extensions:  CPP
   default-language:    Haskell2010
   main-is:             BorderDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
@@ -397,7 +398,7 @@
   default-extensions:  CPP
   default-language:    Haskell2010
   main-is:             ProgressBarDemo.hs
-  build-depends:       base <= 5,
+  build-depends:       base,
                        brick,
                        vty >= 5.18.1,
                        text,
diff --git a/docs/guide.rst b/docs/guide.rst
--- a/docs/guide.rst
+++ b/docs/guide.rst
@@ -922,22 +922,25 @@
 Some terminal emulators support "bracketed paste" support. This feature
 enables OS-level paste operations to send the pasted content as a
 single chunk of data and bypass the usual input processing that the
-application does. This enales more secure handling of pasted data since
-the application can detect that a pasted occurred and avoid processing
+application does. This enables more secure handling of pasted data since
+the application can detect that a paste occurred and avoid processing
 the pasted data as ordinary keyboard input. For more information, see
 `bracketed paste mode`_.
 
 The Vty library used by brick provides support for bracketed pastes, but
 this mode must be enabled. To enable paste mode, we need to get access
-to the Vty library handle in ``EventM``:
+to the Vty library handle in ``EventM`` (in e.g. ``appHandleEvent``):
 
 .. code:: haskell
 
+   import Control.Monad (when)
+   import qualified Graphics.Vty as V
+
    do
      vty <- Brick.Main.getVtyHandle
-     let output = outputIface vty
-     when (supportsMode output BracketedPaste) $
-         liftIO $ setMode output BracketedPaste True
+     let output = V.outputIface vty
+     when (V.supportsMode output V.BracketedPaste) $
+         liftIO $ V.setMode output V.BracketedPaste True
 
 Once enabled, paste mode will generate Vty ``EvPaste`` events. These
 events will give you the entire pasted content as a ``ByteString`` which
diff --git a/programs/AttrDemo.hs b/programs/AttrDemo.hs
--- a/programs/AttrDemo.hs
+++ b/programs/AttrDemo.hs
@@ -1,7 +1,10 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import Graphics.Vty
   ( Attr, white, blue, cyan, green, red, yellow
   , black, withURL
diff --git a/programs/CustomEventDemo.hs b/programs/CustomEventDemo.hs
--- a/programs/CustomEventDemo.hs
+++ b/programs/CustomEventDemo.hs
@@ -1,12 +1,15 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
 import Lens.Micro ((^.), (&), (.~), (%~))
 import Lens.Micro.TH (makeLenses)
 import Control.Monad (void, forever)
 import Control.Concurrent (threadDelay, forkIO)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import qualified Graphics.Vty as V
 
 import Brick.BChan
diff --git a/programs/DialogDemo.hs b/programs/DialogDemo.hs
--- a/programs/DialogDemo.hs
+++ b/programs/DialogDemo.hs
@@ -1,7 +1,10 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import qualified Graphics.Vty as V
 
 import qualified Brick.Main as M
diff --git a/programs/ListDemo.hs b/programs/ListDemo.hs
--- a/programs/ListDemo.hs
+++ b/programs/ListDemo.hs
@@ -1,9 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
 import Lens.Micro ((^.))
 import Control.Monad (void)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import Data.Maybe (fromMaybe)
 import qualified Graphics.Vty as V
 
diff --git a/programs/ListViDemo.hs b/programs/ListViDemo.hs
--- a/programs/ListViDemo.hs
+++ b/programs/ListViDemo.hs
@@ -1,9 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
 import Control.Monad (void)
 import Data.Maybe (fromMaybe)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import qualified Graphics.Vty as V
 import Lens.Micro ((^.))
 
diff --git a/programs/ProgressBarDemo.hs b/programs/ProgressBarDemo.hs
--- a/programs/ProgressBarDemo.hs
+++ b/programs/ProgressBarDemo.hs
@@ -1,8 +1,11 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
 import Control.Monad (void)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import qualified Graphics.Vty as V
 
 import qualified Brick.AttrMap as A
diff --git a/programs/SuspendAndResumeDemo.hs b/programs/SuspendAndResumeDemo.hs
--- a/programs/SuspendAndResumeDemo.hs
+++ b/programs/SuspendAndResumeDemo.hs
@@ -1,11 +1,14 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
 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 Brick.Main
diff --git a/programs/VisibilityDemo.hs b/programs/VisibilityDemo.hs
--- a/programs/VisibilityDemo.hs
+++ b/programs/VisibilityDemo.hs
@@ -1,11 +1,14 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
 module Main where
 
 import Control.Monad (void)
 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 qualified Brick.Types as T
diff --git a/src/Brick/AttrMap.hs b/src/Brick/AttrMap.hs
--- a/src/Brick/AttrMap.hs
+++ b/src/Brick/AttrMap.hs
@@ -48,6 +48,8 @@
 import Data.Monoid
 #endif
 
+import qualified Data.Semigroup as Sem
+
 import qualified Data.Map as M
 import Data.Maybe (catMaybes)
 import Data.List (inits)
@@ -70,9 +72,12 @@
 data AttrName = AttrName [String]
               deriving (Show, Read, Eq, Ord)
 
+instance Sem.Semigroup AttrName where
+    (AttrName as) <> (AttrName bs) = AttrName $ as `mappend` bs
+
 instance Monoid AttrName where
     mempty = AttrName []
-    mappend (AttrName as) (AttrName bs) = AttrName $ as `mappend` bs
+    mappend = (Sem.<>)
 
 instance IsString AttrName where
     fromString = AttrName . (:[])
diff --git a/src/Brick/Forms.hs b/src/Brick/Forms.hs
--- a/src/Brick/Forms.hs
+++ b/src/Brick/Forms.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 -- | 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!
@@ -68,7 +69,9 @@
 where
 
 import Graphics.Vty
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import Data.Maybe (isJust, isNothing)
 import Data.List (elemIndex)
 
diff --git a/src/Brick/Themes.hs b/src/Brick/Themes.hs
--- a/src/Brick/Themes.hs
+++ b/src/Brick/Themes.hs
@@ -77,6 +77,7 @@
 import qualified Data.Text as T
 import qualified Data.Text.IO as T
 import qualified Data.Map as M
+import qualified Data.Semigroup as Sem
 import Data.Tuple (swap)
 import Data.List (intercalate)
 import Data.Bits ((.|.), (.&.))
@@ -101,13 +102,16 @@
                }
                deriving (Eq, Read, Show, Generic)
 
-instance Monoid CustomAttr where
-    mempty = CustomAttr Nothing Nothing Nothing
-    mappend a b =
+instance Sem.Semigroup CustomAttr where
+    a <> b =
         CustomAttr { customFg    = customFg a    <|> customFg b
                    , customBg    = customBg a    <|> customBg b
                    , customStyle = customStyle a <|> customStyle b
                    }
+
+instance Monoid CustomAttr where
+    mempty = CustomAttr Nothing Nothing Nothing
+    mappend = (Sem.<>)
 
 -- | Documentation for a theme's attributes.
 data ThemeDocumentation =
diff --git a/src/Brick/Types/Internal.hs b/src/Brick/Types/Internal.hs
--- a/src/Brick/Types/Internal.hs
+++ b/src/Brick/Types/Internal.hs
@@ -51,6 +51,7 @@
 import Lens.Micro.Internal (Field1, Field2)
 import qualified Data.Set as S
 import qualified Data.Map as M
+import qualified Data.Semigroup as Sem
 import Graphics.Vty (Vty, Event, Button, Modifier, DisplayRegion, Image, emptyImage)
 
 import Brick.Types.TH
@@ -163,9 +164,12 @@
 origin :: Location
 origin = Location (0, 0)
 
+instance Sem.Semigroup Location where
+    (Location (w1, h1)) <> (Location (w2, h2)) = Location (w1+w2, h1+h2)
+
 instance Monoid Location where
     mempty = origin
-    mappend (Location (w1, h1)) (Location (w2, h2)) = Location (w1+w2, h1+h2)
+    mappend = (Sem.<>)
 
 -- | A cursor location.  These are returned by the rendering process.
 data CursorLocation n =
diff --git a/src/Brick/Widgets/Dialog.hs b/src/Brick/Widgets/Dialog.hs
--- a/src/Brick/Widgets/Dialog.hs
+++ b/src/Brick/Widgets/Dialog.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 -- | This module provides a simple dialog widget. You get to pick the
 -- dialog title, if any, as well as its body and buttons.
 --
@@ -40,7 +41,9 @@
 #endif
 
 import Lens.Micro
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import Data.List (intersperse)
 import Graphics.Vty.Input (Event(..), Key(..))
 
diff --git a/src/Brick/Widgets/Edit.hs b/src/Brick/Widgets/Edit.hs
--- a/src/Brick/Widgets/Edit.hs
+++ b/src/Brick/Widgets/Edit.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE CPP #-}
 -- | This module provides a basic text editor widget. You'll need to
 -- embed an 'Editor' in your application state and transform it with
 -- 'handleEditorEvent' when relevant events arrive. To get the contents
@@ -38,7 +39,9 @@
   )
 where
 
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import Lens.Micro
 import Graphics.Vty (Event(..), Key(..), Modifier(..))
 
diff --git a/src/Brick/Widgets/ProgressBar.hs b/src/Brick/Widgets/ProgressBar.hs
--- a/src/Brick/Widgets/ProgressBar.hs
+++ b/src/Brick/Widgets/ProgressBar.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
 -- | This module provides a progress bar widget.
 module Brick.Widgets.ProgressBar
   ( progressBar
@@ -10,7 +11,9 @@
 
 import Lens.Micro ((^.))
 import Data.Maybe (fromMaybe)
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Monoid
+#endif
 import Graphics.Vty (safeWcswidth)
 
 import Brick.Types
diff --git a/src/Data/Text/Markup.hs b/src/Data/Text/Markup.hs
--- a/src/Data/Text/Markup.hs
+++ b/src/Data/Text/Markup.hs
@@ -21,6 +21,7 @@
 import Data.Monoid
 #endif
 
+import qualified Data.Semigroup as Sem
 import Data.String (IsString(..))
 import qualified Data.Text as T
 
@@ -28,10 +29,12 @@
 data Markup a = Markup [(Char, a)]
               deriving Show
 
+instance Sem.Semigroup (Markup a) where
+    (Markup t1) <> (Markup t2) = Markup (t1 `mappend` t2)
+
 instance Monoid (Markup a) where
     mempty = Markup mempty
-    mappend (Markup t1) (Markup t2) =
-        Markup (t1 `mappend` t2)
+    mappend = (Sem.<>)
 
 instance (Monoid a) => IsString (Markup a) where
     fromString = fromText . T.pack
