diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,22 @@
 Brick changelog
 ---------------
 
+0.66
+----
+
+New features:
+ * Added `Brick.Main.makeVisible`, a function to requeste
+   visible regions from `EventM`. This, together with
+   `Brick.Widgets.Core.reportExtent`, can be used to request that a
+   viewport be scrolled to make a specified named region visible on
+   the next redraw. The region must be known to the renderer with
+   `reportExtent` (or something that calls it, like `clickable`). Due to
+   the `Ord` constraint on some of the API calls required to implement
+   this, an `Ord` constraint on the resource name type (`n`) got
+   propagated to various places in the API. But that shouldn't present
+   a problem since other fundamental API calls already required that
+   instance.
+
 0.65.1
 ------
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.65.1
+version:             0.66
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal user interfaces (TUIs) painlessly with 'brick'! You
diff --git a/src/Brick/Forms.hs b/src/Brick/Forms.hs
--- a/src/Brick/Forms.hs
+++ b/src/Brick/Forms.hs
@@ -343,7 +343,7 @@
                       , formFieldConcat = vBox
                       }
 
-renderCheckbox :: Char -> Char -> Char -> T.Text -> n -> Bool -> Bool -> Widget n
+renderCheckbox :: (Ord n) => Char -> Char -> Char -> T.Text -> n -> Bool -> Bool -> Widget n
 renderCheckbox lb check rb label n foc val =
     let addAttr = if foc then withDefAttr focusedFormInputAttr else id
         csr = if foc then putCursor n (Location (1,0)) else id
@@ -469,7 +469,7 @@
                       , formFieldConcat = vBox
                       }
 
-renderRadio :: (Eq a) => Char -> Char -> Char -> a -> n -> T.Text -> Bool -> a -> Widget n
+renderRadio :: (Eq a, Ord n) => Char -> Char -> Char -> a -> n -> T.Text -> Bool -> a -> Widget n
 renderRadio lb check rb val name label foc cur =
     let addAttr = if foc
                   then withDefAttr focusedFormInputAttr
diff --git a/src/Brick/Main.hs b/src/Brick/Main.hs
--- a/src/Brick/Main.hs
+++ b/src/Brick/Main.hs
@@ -13,6 +13,7 @@
   , continueWithoutRedraw
   , halt
   , suspendAndResume
+  , makeVisible
   , lookupViewport
   , lookupExtent
   , findClickedExtents
@@ -275,12 +276,12 @@
                     newVty <- buildVty
                     run newVty (newRS { renderCache = mempty }) newAppState brickChan
 
-    let emptyES = ES [] mempty
-        emptyRS = RS M.empty mempty S.empty mempty mempty
+    let emptyES = ES [] mempty mempty
+        emptyRS = RS M.empty mempty S.empty mempty mempty mempty
         eventRO = EventRO M.empty initialVty mempty emptyRS
 
     (st, eState) <- runStateT (runReaderT (runEventM (appStartEvent app initialAppState)) eventRO) emptyES
-    let initialRS = RS M.empty (esScrollRequests eState) S.empty mempty []
+    let initialRS = RS M.empty (esScrollRequests eState) S.empty mempty [] (requestedVisibleNames eState)
     brickChan <- newBChan 20
     run initialVty initialRS st brickChan
 
@@ -364,7 +365,7 @@
                 _ -> return (e, firstRS, exts)
         _ -> return (e, firstRS, exts)
 
-    let emptyES = ES [] mempty
+    let emptyES = ES [] mempty mempty
         eventRO = EventRO (viewportMap nextRS) vty nextExts nextRS
 
     (next, eState) <- runStateT (runReaderT (runEventM (appHandleEvent app appState e'))
@@ -373,6 +374,7 @@
            , nextRS { rsScrollRequests = esScrollRequests eState
                     , renderCache = applyInvalidations (cacheInvalidateRequests eState) $
                                     renderCache nextRS
+                    , requestedVisibleNames_ = requestedVisibleNames eState
                     }
            , nextExts
            )
@@ -579,3 +581,11 @@
 -- to the user.
 suspendAndResume :: IO s -> EventM n (Next s)
 suspendAndResume = return . SuspendAndResume
+
+-- | Request that the specified UI element be made visible on the
+-- next rendering. This is provided to allow event handlers to make
+-- visibility requests in the same way that the 'visible' function does
+-- at rendering time.
+makeVisible :: (Ord n) => n -> EventM n ()
+makeVisible n = EventM $ do
+    lift $ modify (\s -> s { requestedVisibleNames = S.insert n $ requestedVisibleNames s })
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
@@ -66,6 +66,7 @@
   , clickableNamesL
   , renderCacheL
   , observedNamesL
+  , requestedVisibleNames_L
   , vpSize
   , vpLeft
   , vpTop
@@ -138,6 +139,7 @@
        , observedNames :: !(S.Set n)
        , renderCache :: !(M.Map n ([n], Result n))
        , clickableNames :: ![n]
+       , requestedVisibleNames_ :: !(S.Set n)
        } deriving (Read, Show, Generic, NFData)
 
 -- | The type of the rendering monad. This monad is used by the
@@ -222,6 +224,7 @@
 
 data EventState n = ES { esScrollRequests :: [(n, ScrollRequest)]
                        , cacheInvalidateRequests :: S.Set (CacheInvalidateRequest n)
+                       , requestedVisibleNames :: S.Set n
                        }
 
 -- | An extent of a named area: its size, location, and origin.
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
@@ -225,7 +225,13 @@
 
 -- | Render the specified widget and record its rendering extent using
 -- the specified name (see also 'lookupExtent').
-reportExtent :: n -> Widget n -> Widget n
+--
+-- This function is the counterpart to 'makeVisible'; any visibility
+-- requests made with 'makeVisible' must have a corresponding
+-- 'reportExtent' in order to work. The 'clickable' function will also
+-- work for this purpose to tell the renderer about the clickable
+-- region.
+reportExtent :: (Ord n) => n -> Widget n -> Widget n
 reportExtent n p =
     Widget (hSize p) (vSize p) $ do
         result <- render p
@@ -233,10 +239,21 @@
             sz = ( result^.imageL.to V.imageWidth
                  , result^.imageL.to V.imageHeight
                  )
-        return $ result & extentsL %~ (ext:)
+        -- If the reported extent also has a visibility request
+        -- from EventM via makeVisible, add a visibility request to
+        -- the render state so this gets scrolled into view by any
+        -- containing viewport.
+        vReqs <- use requestedVisibleNames_L
+        let addVisReq = if sz^._1 > 0 && sz^._2 > 0 && n `S.member` vReqs
+                        then visibilityRequestsL %~ (VR (Location (0, 0)) sz :)
+                        else id
+        return $ addVisReq $ result & extentsL %~ (ext:)
 
 -- | Request mouse click events on the specified widget.
-clickable :: n -> Widget n -> Widget n
+--
+-- Regions used with 'clickable' can be scrolled into view with
+-- 'makeVisible'.
+clickable :: (Ord n) => n -> Widget n -> Widget n
 clickable n p =
     Widget (hSize p) (vSize p) $ do
         clickableNamesL %= (n:)
@@ -1400,7 +1417,8 @@
 scrollbarHandleAttr :: AttrName
 scrollbarHandleAttr = scrollbarAttr <> "handle"
 
-maybeClick :: n
+maybeClick :: (Ord n)
+           => n
            -> Maybe (ClickableScrollbarElement -> n -> n)
            -> ClickableScrollbarElement
            -> Widget n
@@ -1416,7 +1434,8 @@
 -- @withVScrollBarRenderer@. This is exposed so that if you want to
 -- render a scroll bar of your own, you can do so outside the @viewport@
 -- context.
-verticalScrollbar :: ScrollbarRenderer n
+verticalScrollbar :: (Ord n)
+                  => ScrollbarRenderer n
                   -- ^ The renderer to use.
                   -> n
                   -- ^ The viewport name associated with this scroll
@@ -1442,7 +1461,8 @@
            hLimit 1 $ withDefAttr scrollbarHandleAttr $ renderScrollbarHandleAfter vsRenderer
          ]
 
-verticalScrollbar' :: ScrollbarRenderer n
+verticalScrollbar' :: (Ord n)
+                   => ScrollbarRenderer n
                    -- ^ The renderer to use.
                    -> n
                    -- ^ The viewport name associated with this scroll
@@ -1512,7 +1532,8 @@
 -- @withHScrollBarRenderer@. This is exposed so that if you want to
 -- render a scroll bar of your own, you can do so outside the @viewport@
 -- context.
-horizontalScrollbar :: ScrollbarRenderer n
+horizontalScrollbar :: (Ord n)
+                    => ScrollbarRenderer n
                     -- ^ The renderer to use.
                     -> n
                     -- ^ The viewport name associated with this scroll
@@ -1539,7 +1560,8 @@
            vLimit 1 $ withDefAttr scrollbarHandleAttr $ renderScrollbarHandleAfter hsRenderer
          ]
 
-horizontalScrollbar' :: ScrollbarRenderer n
+horizontalScrollbar' :: (Ord n)
+                     => ScrollbarRenderer n
                      -- ^ The renderer to use.
                      -> n
                      -- ^ The viewport name associated with this scroll
