diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,31 @@
 Brick changelog
 ---------------
 
+0.15
+----
+
+Demo changes:
+* MouseDemo: add an editor and use mouse events to move the cursor
+* MouseDemo: Enhance MouseDemo to show interaction between 'clickable'
+  and viewports (thanks Kevin Quick)
+
+New features:
+* Editors now report mouse click events
+
+API changes:
+* Rename TerminalLocation row/column fields to avoid commonplace name
+  clashes; rename row/column to locationRow/locationColumn (fixes #96)
+
+Bug fixes:
+* Core: make cropToContext also crop extents (fixes #101)
+* viewport: if the sub-widget is not rendered, also cull all extents and
+  cursor locations
+
+Documentation changes:
+* User Guide updates: minor fixes, updates to content on custom widgets,
+  wide character support, and examples (thanks skapazzo@inventati.org,
+  Kevin Quick)
+
 0.14
 ----
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.14
+version:             0.15
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal applications painlessly with 'brick'! You write an
@@ -164,7 +164,8 @@
                        data-default,
                        text,
                        microlens >= 0.3.0.0,
-                       microlens-th
+                       microlens-th,
+                       text-zipper
 
 executable brick-layer-demo
   if !flag(demos)
diff --git a/docs/guide.rst b/docs/guide.rst
--- a/docs/guide.rst
+++ b/docs/guide.rst
@@ -423,7 +423,7 @@
   cursor position.
 
 For example, this widget requests a cursor placement on the first
-"``o``" in "``foo``" assocated with the cursor name "``myCursor``":
+"``o``" in "``foo``" associated with the cursor name "``myCursor``":
 
 .. code:: haskell
 
@@ -726,6 +726,37 @@
 * ``Brick.Widgets.Core.withDefAttr``
 * ``Brick.Widgets.Core.overrideAttr``
 
+Wide Character Support and the TextWidth class
+==============================================
+
+Brick supports rendering wide characters in all widgets, and the brick
+editor supports entering and editing wide characters. Wide characters
+are those such as many Asian characters and emoji that need more than
+a single terminal column to be displayed. Brick relies on Vty's use of
+the `utf8proc`_ library to determine the column width of each character
+rendered.
+
+As a result of supporting wide characters, it is important to know that
+computing the length of a string to determine its screen width will
+*only* work for single-column characters. So, for example, if you want
+to support wide characters in your application, this will not work:
+
+.. code:: haskell
+
+   let width = Data.Text.length t
+
+because if the string contains any wide characters, their widths
+will not be counted properly. In order to get this right, use the
+``TextWidth`` type class to compute the width:
+
+.. code:: haskell
+
+   let width = Brick.Widgets.Core.textWidth t
+
+The ``TextWidth`` type class uses Vty's character width routine (and
+thus ``utf8proc``) to compute the correct width. If you need to compute
+the width of a single character, use ``Graphics.Text.wcwidth``.
+
 Extents
 =======
 
@@ -783,9 +814,11 @@
 
    do
      vty <- Brick.Main.getVtyHandle
-     let output = outputIface vty
-     when (supportsMode output BracketedPaste) $
-       liftIO $ setMode output BracketedPaste True
+     case vty of
+       Nothing -> return ()
+       Just v -> let output = outputIface v
+                 in when (supportsMode output BracketedPaste) $
+                      liftIO $ setMode output BracketedPaste True
 
 Once enabled, paste mode will generate Vty ``EvPaste`` events. These
 events will give you the entire pasted content as a ``ByteString`` which
@@ -804,9 +837,11 @@
 
    do
      vty <- Brick.Main.getVtyHandle
-     let output = outputIface vty
-     when (supportsMode output Mouse) $
-       liftIO $ setMode output Mouse True
+     case vty of
+       Nothing -> return ()
+       Just v -> let output = outputIface vt
+                 in when (supportsMode output Mouse) $
+                      liftIO $ setMode output Mouse True
 
 Bear in mind that some terminals do not support mouse interaction, so
 use Vty's ``getModeStatus`` to find out whether your terminal will
@@ -1107,31 +1142,41 @@
      -- Invalidate the entire cache (useful on a resize):
      Brick.Main.invalidateCache
 
-Implementing Your Own Widgets
-=============================
+Implementing Custom Widgets
+===========================
 
-``brick`` exposes all of the internals you need to implement your own
-widgets. Those internals, together with ``Graphics.Vty``, can be used to
-create widgets from the ground up. We start by writing a constructor
-function:
+``brick`` exposes all of the internals you need to implement your
+own widgets. Those internals, together with ``Graphics.Vty``, can be
+used to create widgets from the ground up. You'll need to implement
+your own widget if you can't write what you need in terms of existing
+combinators. For example, an ordinary widget like
 
 .. code:: haskell
 
-   myWidget :: ... -> Widget n
-   myWidget ... =
-       Widget Fixed Fixed $ do
-           ...
+   myWidget :: Widget n
+   myWidget = str "Above" <=> str "Below"
 
-We specify the horizontal and vertical growth policies of the widget
-as ``Fixed`` in this example, although they should be specified
-appropriately (see `How Widgets and Rendering Work`_). Lastly we specify
-the *rendering function*, a function of type
+can be expressed with ``<=>`` and ``str`` and needs no custom behavior.
+But suppose we want to write a widget that renders some string followed
+by the number of columns in the space available to the widget. We can't
+do this without writing a custom widget because we need access to the
+rendering context. We can write such a widget as follows:
 
 .. code:: haskell
 
-   render :: RenderM n Result
+   customWidget :: String -> Widget n
+   customWidget s =
+       Widget Fixed Fixed $ do
+           ctx <- getContext
+           render $ str (s <> " " <> show (ctx^.availWidthL))
 
-which is a function returning a ``Brick.Types.Result``:
+The ``Widget`` constructor takes the horizontal and vertical growth
+policies as described in `How Widgets and Rendering Work`_. Here we just
+provide ``Fixed`` for both because the widget will not change behavior
+if we give it more space. We then get the rendering context and append
+the context's available columns to the provided string. Lastly we call
+``render`` to render the widget we made with ``str``. The ``render``
+function returns a ``Brick.Types.Result`` value:
 
 .. code:: haskell
 
@@ -1139,11 +1184,14 @@
         Result { image              :: Graphics.Vty.Image
                , cursors            :: [Brick.Types.CursorLocation n]
                , visibilityRequests :: [Brick.Types.VisibilityRequest]
+               , extents            :: [Extent n]
                }
 
-The ``RenderM`` monad gives us access to the rendering context (see `How
-Widgets and Rendering Work`_) via the ``Brick.Types.getContext``
-function. The context type is:
+The rendering function runs in the ``RenderM`` monad, which gives us
+access to the rendering context (see `How Widgets and Rendering Work`_)
+via the ``Brick.Types.getContext`` function as shown above. The context
+tells us about the dimensions of the rendering area and the current
+attribute state of the renderer, among other things:
 
 .. code:: haskell
 
@@ -1157,16 +1205,16 @@
 
 and has lens fields exported as described in `Conventions`_.
 
-The job of the rendering function is to return a rendering result which,
-at a minimum, means producing a ``vty`` ``Image``. In addition, if you
-so choose, you can also return one or more cursor positions in the
-``cursors`` field of the ``Result`` as well as visibility requests (see
-`Viewports`_) in the ``visibilityRequests`` field. Returned visibility
-requests and cursor positions should be relative to the upper-left
-corner of your widget, ``Location (0, 0)``. When your widget is placed
-in others, such as boxes, the ``Result`` data you returned will be
-offset (as described in `Rendering Sub-Widgets`_) to result in correct
-coordinates once the entire interface has been rendered.
+As shown here, the job of the rendering function is to return a
+rendering result which means producing a ``vty`` ``Image``. In addition,
+if you so choose, you can also return one or more cursor positions in
+the ``cursors`` field of the ``Result`` as well as visibility requests
+(see `Viewports`_) in the ``visibilityRequests`` field. Returned
+visibility requests and cursor positions should be relative to the
+upper-left corner of your widget, ``Location (0, 0)``. When your widget
+is placed in others, such as boxes, the ``Result`` data you returned
+will be offset (as described in `Rendering Sub-Widgets`_) to result in
+correct coordinates once the entire interface has been rendered.
 
 Using the Rendering Context
 ---------------------------
@@ -1195,11 +1243,11 @@
 Rendering Sub-Widgets
 ---------------------
 
-If your custom widget wraps another, then in addition to rendering the
-wrapped widget and augmenting its returned ``Result`` *it must also
-translate the resulting cursor locations and visibility requests*.
-This is vital to maintaining the correctness of cursor locations and
-visbility locations as widget layout proceeds. To do so, use the
+If your custom widget wraps another, then in addition to rendering
+the wrapped widget and augmenting its returned ``Result`` *it must
+also translate the resulting cursor locations, visibility requests,
+and extents*. This is vital to maintaining the correctness of
+rendering metadata as widget layout proceeds. To do so, use the
 ``Brick.Widgets.Core.addResultOffset`` function to offset the elements
 of a ``Result`` by a specified amount. The amount depends on the nature
 of the offset introduced by your wrapper widget's logic.
@@ -1231,3 +1279,4 @@
 .. _Hackage: http://hackage.haskell.org/
 .. _microlens: http://hackage.haskell.org/package/microlens
 .. _bracketed paste mode: https://cirw.in/blog/bracketed-paste
+.. _utf8proc: http://julialang.org/utf8proc/
diff --git a/programs/LayerDemo.hs b/programs/LayerDemo.hs
--- a/programs/LayerDemo.hs
+++ b/programs/LayerDemo.hs
@@ -9,7 +9,7 @@
 import qualified Graphics.Vty as V
 
 import qualified Brick.Types as T
-import Brick.Types (rowL, columnL, Widget)
+import Brick.Types (locationRowL, locationColumnL, Widget)
 import qualified Brick.Main as M
 import qualified Brick.Widgets.Border as B
 import qualified Brick.Widgets.Center as C
@@ -44,15 +44,23 @@
     B.border $ str "Bottom layer\n(Ctrl-arrow keys move)"
 
 appEvent :: St -> T.BrickEvent () e -> T.EventM () (T.Next St)
-appEvent st (T.VtyEvent (V.EvKey V.KDown []))  = M.continue $ st & topLayerLocation.rowL %~ (+ 1)
-appEvent st (T.VtyEvent (V.EvKey V.KUp []))    = M.continue $ st & topLayerLocation.rowL %~ (subtract 1)
-appEvent st (T.VtyEvent (V.EvKey V.KRight [])) = M.continue $ st & topLayerLocation.columnL %~ (+ 1)
-appEvent st (T.VtyEvent (V.EvKey V.KLeft []))  = M.continue $ st & topLayerLocation.columnL %~ (subtract 1)
+appEvent st (T.VtyEvent (V.EvKey V.KDown []))  =
+    M.continue $ st & topLayerLocation.locationRowL %~ (+ 1)
+appEvent st (T.VtyEvent (V.EvKey V.KUp []))    =
+    M.continue $ st & topLayerLocation.locationRowL %~ (subtract 1)
+appEvent st (T.VtyEvent (V.EvKey V.KRight [])) =
+    M.continue $ st & topLayerLocation.locationColumnL %~ (+ 1)
+appEvent st (T.VtyEvent (V.EvKey V.KLeft []))  =
+    M.continue $ st & topLayerLocation.locationColumnL %~ (subtract 1)
 
-appEvent st (T.VtyEvent (V.EvKey V.KDown  [V.MCtrl])) = M.continue $ st & bottomLayerLocation.rowL %~ (+ 1)
-appEvent st (T.VtyEvent (V.EvKey V.KUp    [V.MCtrl])) = M.continue $ st & bottomLayerLocation.rowL %~ (subtract 1)
-appEvent st (T.VtyEvent (V.EvKey V.KRight [V.MCtrl])) = M.continue $ st & bottomLayerLocation.columnL %~ (+ 1)
-appEvent st (T.VtyEvent (V.EvKey V.KLeft  [V.MCtrl])) = M.continue $ st & bottomLayerLocation.columnL %~ (subtract 1)
+appEvent st (T.VtyEvent (V.EvKey V.KDown  [V.MCtrl])) =
+    M.continue $ st & bottomLayerLocation.locationRowL %~ (+ 1)
+appEvent st (T.VtyEvent (V.EvKey V.KUp    [V.MCtrl])) =
+    M.continue $ st & bottomLayerLocation.locationRowL %~ (subtract 1)
+appEvent st (T.VtyEvent (V.EvKey V.KRight [V.MCtrl])) =
+    M.continue $ st & bottomLayerLocation.locationColumnL %~ (+ 1)
+appEvent st (T.VtyEvent (V.EvKey V.KLeft  [V.MCtrl])) =
+    M.continue $ st & bottomLayerLocation.locationColumnL %~ (subtract 1)
 
 appEvent st (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt st
 appEvent st _ = M.continue st
diff --git a/programs/MouseDemo.hs b/programs/MouseDemo.hs
--- a/programs/MouseDemo.hs
+++ b/programs/MouseDemo.hs
@@ -3,7 +3,7 @@
 module Main where
 
 import Control.Applicative ((<$>))
-import Lens.Micro ((^.), (&), (.~))
+import Lens.Micro ((^.), (&), (.~), (%~))
 import Lens.Micro.TH (makeLenses)
 import Control.Monad (void)
 import Data.Monoid ((<>))
@@ -12,17 +12,23 @@
 import qualified Brick.Types as T
 import Brick.AttrMap
 import Brick.Util
-import Brick.Types (Widget)
+import Brick.Types (Widget, ViewportType(Vertical))
 import qualified Brick.Main as M
+import qualified Brick.Widgets.Edit as E
 import qualified Brick.Widgets.Center as C
 import qualified Brick.Widgets.Border as B
 import Brick.Widgets.Core
+import Data.Text.Zipper (moveCursor)
+import Data.Tuple (swap)
 
-data Name = Info | Button1 | Button2 | Button3 deriving (Show, Ord, Eq)
+data Name = Info | Button1 | Button2 | Button3 | Prose | TextBox
+          deriving (Show, Ord, Eq)
 
 data St =
     St { _clicked :: [T.Extent Name]
        , _lastReportedClick :: Maybe (Name, T.Location)
+       , _prose :: String
+       , _edit :: E.Editor String Name
        }
 
 makeLenses ''St
@@ -30,12 +36,17 @@
 drawUi :: St -> [Widget Name]
 drawUi st =
     [ buttonLayer st
+    , proseLayer st
     , infoLayer st
     ]
 
 buttonLayer :: St -> Widget Name
 buttonLayer st =
-    C.centerLayer $ hBox $ padAll 1 <$> buttons
+    C.vCenterLayer $
+      C.hCenterLayer (padBottom (T.Pad 1) $ str "Click a button:") <=>
+      C.hCenterLayer (hBox $ padLeftRight 1 <$> buttons) <=>
+      C.hCenterLayer (padTopBottom 1 $ str "Or enter text and then click in this editor:") <=>
+      C.hCenterLayer (vLimit 3 $ hLimit 50 $ E.renderEditor True (st^.edit))
     where
         buttons = mkButton <$> buttonData
         buttonData = [ (Button1, "Button 1", "button1")
@@ -51,6 +62,18 @@
                padLeftRight (if wasClicked then 2 else 3) $
                str (if wasClicked then "<" <> label <> ">" else label)
 
+proseLayer :: St -> Widget Name
+proseLayer st =
+  B.border $
+  C.hCenterLayer $
+  vLimit 8 $
+  -- n.b. if clickable and viewport are inverted here, click event
+  -- coordinates will only identify the viewable range, not the actual
+  -- editor widget coordinates.
+  viewport Prose Vertical $
+  clickable Prose $
+  vBox $ map str $ lines (st^.prose)
+
 infoLayer :: St -> Widget Name
 infoLayer st = T.Widget T.Fixed T.Fixed $ do
     c <- T.getContext
@@ -63,10 +86,16 @@
                C.hCenter (str ("Last reported click: " <> msg))
 
 appEvent :: St -> T.BrickEvent Name e -> T.EventM Name (T.Next St)
-appEvent st (T.MouseDown n _ _ loc) = M.continue $ st & lastReportedClick .~ Just (n, loc)
+appEvent st (T.MouseDown n _ _ loc) = do
+    let T.Location pos = loc
+    M.continue $ st & lastReportedClick .~ Just (n, loc)
+                    & edit %~ E.applyEdit (if n == TextBox then moveCursor (swap pos) else id)
 appEvent st (T.MouseUp _ _ _) = M.continue $ st & lastReportedClick .~ Nothing
 appEvent st (T.VtyEvent (V.EvMouseUp _ _ _)) = M.continue $ st & lastReportedClick .~ Nothing
+appEvent st (T.VtyEvent (V.EvKey V.KUp [V.MCtrl])) = M.vScrollBy (M.viewportScroll Prose) (-1) >> M.continue st
+appEvent st (T.VtyEvent (V.EvKey V.KDown [V.MCtrl])) = M.vScrollBy (M.viewportScroll Prose) 1 >> M.continue st
 appEvent st (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt st
+appEvent st (T.VtyEvent ev) = M.continue =<< T.handleEventLensed st edit E.handleEditorEvent ev
 appEvent st _ = M.continue st
 
 aMap :: AttrMap
@@ -75,6 +104,7 @@
     , ("button1",   V.white `on` V.cyan)
     , ("button2",   V.white `on` V.green)
     , ("button3",   V.white `on` V.blue)
+    , (E.editFocusedAttr, V.black `on` V.yellow)
     ]
 
 app :: M.App St e Name
@@ -83,7 +113,7 @@
           , M.appStartEvent = return
           , M.appHandleEvent = appEvent
           , M.appAttrMap = const aMap
-          , M.appChooseCursor = M.neverShowCursor
+          , M.appChooseCursor = M.showFirstCursor
           }
 
 main :: IO ()
@@ -94,3 +124,23 @@
           return v
 
     void $ M.customMain buildVty Nothing app $ St [] Nothing
+           "Press Ctrl-up and Ctrl-down arrow keys to scroll, ESC to quit.\n\
+           \Observe 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"
+           (E.editor TextBox (str . unlines) Nothing "")
diff --git a/src/Brick/Main.hs b/src/Brick/Main.hs
--- a/src/Brick/Main.hs
+++ b/src/Brick/Main.hs
@@ -238,30 +238,30 @@
         VtyEvent (EvMouseDown c r button mods) -> do
             let matching = findClickedExtents_ (c, r) exts
             case matching of
-                (Extent n (Location (ec, er)) _:_) ->
+                (Extent n (Location (ec, er)) _ (Location (oC, oR)):_) ->
                     -- If the clicked extent was registered as
                     -- clickable, send a click event. Otherwise, just
                     -- send the raw mouse event
                     case n `elem` firstRS^.clickableNamesL of
                         True -> do
                             let localCoords = Location (lc, lr)
-                                lc = c - ec
-                                lr = r - er
+                                lc = c - ec + oC
+                                lr = r - er + oR
                             return (MouseDown n button mods localCoords, firstRS, exts)
                         False -> return (e, firstRS, exts)
                 _ -> return (e, firstRS, exts)
         VtyEvent (EvMouseUp c r button) -> do
             let matching = findClickedExtents_ (c, r) exts
             case matching of
-                (Extent n (Location (ec, er)) _:_) ->
+                (Extent n (Location (ec, er)) _ (Location (oC, oR)):_) ->
                     -- If the clicked extent was registered as
                     -- clickable, send a click event. Otherwise, just
                     -- send the raw mouse event
                     case n `elem` firstRS^.clickableNamesL of
                         True -> do
                             let localCoords = Location (lc, lr)
-                                lc = c - ec
-                                lr = r - er
+                                lc = c - ec + oC
+                                lr = r - er + oR
                             return (MouseUp n button localCoords, firstRS, exts)
                         False -> return (e, firstRS, exts)
                 _ -> return (e, firstRS, exts)
@@ -294,7 +294,7 @@
 -- | Did the specified mouse coordinates (column, row) intersect the
 -- specified extent?
 clickedExtent :: (Int, Int) -> Extent n -> Bool
-clickedExtent (c, r) (Extent _ (Location (lc, lr)) (w, h)) =
+clickedExtent (c, r) (Extent _ (Location (lc, lr)) (w, h) _) =
    c >= lc && c < (lc + w) &&
    r >= lr && r < (lr + h)
 
@@ -303,7 +303,7 @@
 lookupExtent :: (Eq n) => n -> EventM n (Maybe (Extent n))
 lookupExtent n = EventM $ asks (listToMaybe . filter f . latestExtents)
     where
-        f (Extent n' _ _) = n == n'
+        f (Extent n' _ _ _) = n == n'
 
 -- | Given a mouse click location, return the extents intersected by the
 -- click. The returned extents are sorted such that the first extent in
@@ -346,7 +346,9 @@
                                         rs
         picWithCursor = case theCursor of
             Nothing -> pic { picCursor = NoCursor }
-            Just cloc -> pic { picCursor = AbsoluteCursor (cloc^.columnL) (cloc^.rowL) }
+            Just cloc -> pic { picCursor = AbsoluteCursor (cloc^.locationColumnL)
+                                                          (cloc^.locationRowL)
+                             }
 
     update vty picWithCursor
 
diff --git a/src/Brick/Types.hs b/src/Brick/Types.hs
--- a/src/Brick/Types.hs
+++ b/src/Brick/Types.hs
@@ -154,10 +154,10 @@
 attrL = to (\c -> attrMapLookup (c^.ctxAttrNameL) (c^.ctxAttrMapL))
 
 instance TerminalLocation (CursorLocation n) where
-    columnL = cursorLocationL._1
-    column = column . cursorLocation
-    rowL = cursorLocationL._2
-    row = row . cursorLocation
+    locationColumnL = cursorLocationL._1
+    locationColumn = locationColumn . cursorLocation
+    locationRowL = cursorLocationL._2
+    locationRow = locationRow . cursorLocation
 
 -- | Given an attribute name, obtain the attribute for the attribute
 -- name by consulting the context's attribute map.
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
@@ -103,9 +103,12 @@
                        , cacheInvalidateRequests :: [CacheInvalidateRequest n]
                        }
 
--- | An extent of a named area indicating the location of its upper-left
--- corner and its size (width, height).
-data Extent n = Extent n Location (Int, Int)
+-- | An extent of a named area: its size, location, and origin.
+data Extent n = Extent { extentName      :: n
+                       , extentUpperLeft :: Location
+                       , extentSize      :: (Int, Int)
+                       , extentOffset    :: Location
+                       }
               deriving (Show)
 
 data EventRO n = EventRO { eventViewportMap :: M.Map n Viewport
@@ -143,17 +146,18 @@
 -- | The class of types that behave like terminal locations.
 class TerminalLocation a where
     -- | Get the column out of the value
-    columnL :: Lens' a Int
-    column :: a -> Int
+    locationColumnL :: Lens' a Int
+    locationColumn :: a -> Int
+
     -- | Get the row out of the value
-    rowL :: Lens' a Int
-    row :: a -> Int
+    locationRowL :: Lens' a Int
+    locationRow :: a -> Int
 
 instance TerminalLocation Location where
-    columnL = _1
-    column (Location t) = fst t
-    rowL = _2
-    row (Location t) = snd t
+    locationColumnL = _1
+    locationColumn (Location t) = fst t
+    locationRowL = _2
+    locationRow (Location t) = snd t
 
 -- | The origin (upper-left corner).
 origin :: Location
diff --git a/src/Brick/Widgets/Center.hs b/src/Brick/Widgets/Center.hs
--- a/src/Brick/Widgets/Center.hs
+++ b/src/Brick/Widgets/Center.hs
@@ -153,7 +153,7 @@
       c <- getContext
       let centerW = c^.availWidthL `div` 2
           centerH = c^.availHeightL `div` 2
-          off = Location ( centerW - l^.columnL
-                         , centerH - l^.rowL
+          off = Location ( centerW - l^.locationColumnL
+                         , centerH - l^.locationRowL
                          )
       render $ translateBy off p
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
@@ -144,13 +144,15 @@
 -- something and then translate it or otherwise offset it from its
 -- original origin.
 addResultOffset :: Location -> Result n -> Result n
-addResultOffset off = addCursorOffset off . addVisibilityOffset off . addExtentOffset off
+addResultOffset off = addCursorOffset off .
+                      addVisibilityOffset off .
+                      addExtentOffset off
 
 addVisibilityOffset :: Location -> Result n -> Result n
 addVisibilityOffset off r = r & visibilityRequestsL.each.vrPositionL %~ (off <>)
 
 addExtentOffset :: Location -> Result n -> Result n
-addExtentOffset off r = r & extentsL.each %~ (\(Extent n l sz) -> Extent n (off <> l) sz)
+addExtentOffset off r = r & extentsL.each %~ (\(Extent n l sz o) -> Extent n (off <> l) sz o)
 
 -- | Render the specified widget and record its rendering extent using
 -- the specified name (see also 'lookupExtent').
@@ -158,7 +160,7 @@
 reportExtent n p =
     Widget (hSize p) (vSize p) $ do
         result <- render p
-        let ext = Extent n (Location (0, 0)) sz
+        let ext = Extent n (Location (0, 0)) sz (Location (0, 0))
             sz = ( result^.imageL.to V.imageWidth
                  , result^.imageL.to V.imageHeight
                  )
@@ -174,7 +176,7 @@
 addCursorOffset :: Location -> Result n -> Result n
 addCursorOffset off r =
     let onlyVisible = filter isVisible
-        isVisible l = l^.columnL >= 0 && l^.rowL >= 0
+        isVisible l = l^.locationColumnL >= 0 && l^.locationRowL >= 0
     in r & cursorsL %~ (\cs -> onlyVisible $ (`clOffset` off) <$> cs)
 
 unrestricted :: Int
@@ -550,16 +552,16 @@
 raw img = Widget Fixed Fixed $ return $ def & imageL .~ img
 
 -- | Translate the specified widget by the specified offset amount.
--- Defers to the translated width for growth policy.
+-- Defers to the translated widget for growth policy.
 translateBy :: Location -> Widget n -> Widget n
 translateBy off p =
     Widget (hSize p) (vSize p) $ do
       result <- render p
       return $ addResultOffset off
-             $ result & imageL %~ (V.translate (off^.columnL) (off^.rowL))
+             $ result & imageL %~ (V.translate (off^.locationColumnL) (off^.locationRowL))
 
 -- | Crop the specified widget on the left by the specified number of
--- columns. Defers to the translated width for growth policy.
+-- columns. Defers to the cropped widget for growth policy.
 cropLeftBy :: Int -> Widget n -> Widget n
 cropLeftBy cols p =
     Widget (hSize p) (vSize p) $ do
@@ -570,7 +572,7 @@
              $ result & imageL %~ cropped
 
 -- | Crop the specified widget on the right by the specified number of
--- columns. Defers to the translated width for growth policy.
+-- columns. Defers to the cropped widget for growth policy.
 cropRightBy :: Int -> Widget n -> Widget n
 cropRightBy cols p =
     Widget (hSize p) (vSize p) $ do
@@ -580,7 +582,7 @@
       return $ result & imageL %~ cropped
 
 -- | Crop the specified widget on the top by the specified number of
--- rows. Defers to the translated width for growth policy.
+-- rows. Defers to the cropped widget for growth policy.
 cropTopBy :: Int -> Widget n -> Widget n
 cropTopBy rows p =
     Widget (hSize p) (vSize p) $ do
@@ -591,7 +593,7 @@
              $ result & imageL %~ cropped
 
 -- | Crop the specified widget on the bottom by the specified number of
--- rows. Defers to the translated width for growth policy.
+-- rows. Defers to the cropped widget for growth policy.
 cropBottomBy :: Int -> Widget n -> Widget n
 cropBottomBy rows p =
     Widget (hSize p) (vSize p) $ do
@@ -772,6 +774,8 @@
       case translatedSize of
           (0, 0) -> return $ translated & imageL .~ (V.charFill (c^.attrL) ' ' (c^.availWidthL) (c^.availHeightL))
                                         & visibilityRequestsL .~ mempty
+                                        & extentsL .~ mempty
+                                        & cursorsL .~ mempty
           _ -> render $ cropToContext
                       $ padBottom Max
                       $ padRight Max
@@ -820,9 +824,9 @@
     where
         curStart = vp^.vpTop
         curEnd = curStart + vp^.vpSize._2
-        reqStart = rq^.vrPositionL.rowL
+        reqStart = rq^.vrPositionL.locationRowL
 
-        reqEnd = rq^.vrPositionL.rowL + rq^.vrSizeL._2
+        reqEnd = rq^.vrPositionL.locationRowL + rq^.vrSizeL._2
         newVStart :: Int
         newVStart = if reqStart < vStartEndVisible
                    then reqStart
@@ -834,9 +838,9 @@
     where
         curStart = vp^.vpLeft
         curEnd = curStart + vp^.vpSize._1
-        reqStart = rq^.vrPositionL.columnL
+        reqStart = rq^.vrPositionL.locationColumnL
 
-        reqEnd = rq^.vrPositionL.columnL + rq^.vrSizeL._1
+        reqEnd = rq^.vrPositionL.locationColumnL + rq^.vrSizeL._1
         newHStart :: Int
         newHStart = if reqStart < hStartEndVisible
                    then reqStart
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
@@ -146,7 +146,9 @@
 getEditContents :: Monoid t => Editor t n -> [t]
 getEditContents e = Z.getText $ e^.editContentsL
 
--- | Turn an editor state value into a widget
+-- | Turn an editor state value into a widget. This uses the editor's
+-- name for its scrollable viewport handle and the name is also used to
+-- report mouse events.
 renderEditor :: (Ord n, Show n, Monoid t, TextWidth t, Z.GenericTextZipper t)
              => Bool
              -- ^ Whether the editor has focus. It will report a cursor
@@ -167,6 +169,7 @@
     in withAttr (if foc then editFocusedAttr else editAttr) $
        limit $
        viewport (e^.editorNameL) Both $
+       clickable (e^.editorNameL) $
        (if foc then showCursor (e^.editorNameL) cursorLoc else id) $
        visibleRegion cursorLoc (atCharWidth, 1) $
        e^.editDrawContentsL $
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
@@ -14,6 +14,7 @@
 import Control.Monad.Trans.State.Lazy
 import Control.Monad.Trans.Reader
 import Data.Default
+import Data.Maybe (catMaybes)
 import qualified Graphics.Vty as V
 
 import Brick.Types
@@ -49,4 +50,58 @@
 cropResultToContext :: Result n -> RenderM n (Result n)
 cropResultToContext result = do
     c <- getContext
-    return $ result & imageL %~ (V.crop (max 0 $ c^.availWidthL) (max 0 $ c^.availHeightL))
+    return $ result & imageL   %~ cropImage   c
+                    & cursorsL %~ cropCursors c
+                    & extentsL %~ cropExtents c
+
+cropImage :: Context -> V.Image -> V.Image
+cropImage c = V.crop (max 0 $ c^.availWidthL) (max 0 $ c^.availHeightL)
+
+cropCursors :: Context -> [CursorLocation n] -> [CursorLocation n]
+cropCursors ctx cs = catMaybes $ cropCursor <$> cs
+    where
+        -- A cursor location is removed if it is not within the region
+        -- described by the context.
+        cropCursor c | outOfContext c = Nothing
+                     | otherwise      = Just c
+        outOfContext c =
+            or [ c^.cursorLocationL.locationRowL    < 0
+               , c^.cursorLocationL.locationColumnL < 0
+               , c^.cursorLocationL.locationRowL    >= ctx^.availHeightL
+               , c^.cursorLocationL.locationColumnL >= ctx^.availWidthL
+               ]
+
+cropExtents :: Context -> [Extent n] -> [Extent n]
+cropExtents ctx es = catMaybes $ cropExtent <$> es
+    where
+        -- An extent is cropped in places where it is not within the
+        -- region described by the context.
+        --
+        -- If its entirety is outside the context region, it is dropped.
+        --
+        -- Otherwise its size and upper left corner are adjusted so that
+        -- they are contained within the context region.
+        cropExtent (Extent n (Location (c, r)) (w, h) (Location (oC, oR))) =
+            -- First, clamp the upper-left corner to at least (0, 0).
+            let c' = max c 0
+                r' = max r 0
+                -- Compute deltas for the offset since if the upper-left
+                -- corner moved, so should the offset.
+                dc = c' - c
+                dr = r' - r
+                -- Then, determine the new lower-right corner based on
+                -- the clamped corner.
+                endCol = c' + w
+                endRow = r' + h
+                -- Then clamp the lower-right corner based on the
+                -- context
+                endCol' = min (ctx^.availWidthL) endCol
+                endRow' = min (ctx^.availHeightL) endRow
+                -- Then compute the new width and height from the
+                -- clamped lower-right corner.
+                w' = endCol' - c'
+                h' = endRow' - r'
+                e = Extent n (Location (c', r')) (w', h') (Location (oC + dc, oR + dr))
+            in if w' < 0 || h' < 0
+               then Nothing
+               else Just e
