diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,20 @@
 Brick changelog
 ---------------
 
+1.7
+---
+
+Package changes:
+* Allow building with `base` 4.18 (GHC 9.6) (thanks Mario Lang)
+
+API changes:
+* Added a new function, `Brick.Util.style`, to create a Vty `Attr` from
+  a style value (thanks Amir Dekel)
+
+Other improvements:
+* `Brick.Forms.renderForm` now issues a visibility request for the
+  focused form field, which makes forms usable within viewports.
+
 1.6
 ---
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -92,6 +92,7 @@
 | [`babel-cards`](https://github.com/srhoulam/babel-cards) | A TUI spaced-repetition memorization tool. Similar to Anki. |
 | [`codenames-haskell`](https://github.com/VigneshN1997/codenames-haskell) | An implementation of the Codenames game |
 | [`haradict`](https://github.com/srhoulam/haradict) | A TUI Arabic dictionary powered by [ElixirFM](https://github.com/otakar-smrz/elixir-fm) |
+| [`Giter`](https://gitlab.com/refaelsh/giter) | A UI wrapper around Git CLI inspired by [Magit](https://magit.vc/). |
 
 These third-party packages also extend `brick`:
 
@@ -126,7 +127,7 @@
 Documentation for `brick` comes in a variety of forms:
 
 * [The official brick user guide](https://github.com/jtdaugherty/brick/blob/master/docs/guide.rst)
-* Haddock (all modules)
+* [Haddock documentation](https://hackage.haskell.org/package/brick)
 * [Demo programs](https://github.com/jtdaugherty/brick/blob/master/programs) ([Screenshots](https://github.com/jtdaugherty/brick/blob/master/docs/programs-screenshots.md))
 * [FAQ](https://github.com/jtdaugherty/brick/blob/master/FAQ.md)
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             1.6
+version:             1.7
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal user interfaces (TUIs) painlessly with 'brick'! You
@@ -80,7 +80,7 @@
 
 library
   default-language:    Haskell2010
-  ghc-options:         -Wall -Wcompat -O2
+  ghc-options:         -Wall -Wcompat -O2 -Wunused-packages
   default-extensions:  CPP
   hs-source-dirs:      src
   exposed-modules:
@@ -118,7 +118,7 @@
     Brick.Types.Internal
     Brick.Widgets.Internal
 
-  build-depends:       base >= 4.9.0.0 && < 4.18.0.0,
+  build-depends:       base >= 4.9.0.0 && < 4.19.0.0,
                        vty >= 5.36,
                        bimap >= 0.5 && < 0.6,
                        data-clist >= 0.1,
@@ -132,10 +132,9 @@
                        mtl,
                        config-ini,
                        vector,
-                       contravariant,
                        stm >= 2.4.3,
                        text,
-                       text-zipper >= 0.12,
+                       text-zipper >= 0.13,
                        template-haskell,
                        deepseq >= 1.3 && < 1.5,
                        unix,
diff --git a/src/Brick/Forms.hs b/src/Brick/Forms.hs
--- a/src/Brick/Forms.hs
+++ b/src/Brick/Forms.hs
@@ -710,7 +710,9 @@
 -- 'invalidFormInputAttr' attribute.
 --
 -- Finally, all of the resulting field renderings are concatenated with
--- the form's concatenation function (see 'setFormConcat').
+-- the form's concatenation function (see 'setFormConcat'). A visibility
+-- request is also issued for the currently-focused form field in case
+-- the form is rendered within a viewport.
 renderForm :: (Eq n) => Form s e n -> Widget n
 renderForm (Form es fr _ concatAll) =
     concatAll $ renderFormFieldState fr <$> es
@@ -730,7 +732,8 @@
                                then id
                                else forceAttr invalidFormInputAttr
                 foc = Just n == focusGetCurrent fr
-            in maybeInvalid (renderField foc st) : renderFields fs
+                maybeVisible = if foc then visible else id
+            in (maybeVisible $ maybeInvalid $ renderField foc st) : renderFields fs
     in helper $ concatFields $ renderFields fields
 
 -- | Dispatch an event to the currently focused form field. This handles
diff --git a/src/Brick/Util.hs b/src/Brick/Util.hs
--- a/src/Brick/Util.hs
+++ b/src/Brick/Util.hs
@@ -4,6 +4,7 @@
   , on
   , fg
   , bg
+  , style
   , clOffset
   )
 where
@@ -52,9 +53,14 @@
 fg = (defAttr `withForeColor`)
 
 -- | Create an attribute from the specified background color (the
--- background color is the "default").
+-- foreground color is the "default").
 bg :: Color -> Attr
 bg = (defAttr `withBackColor`)
+
+-- | Create an attribute from the specified style (the colors are the
+-- "default").
+style :: Style -> Attr
+style = (defAttr `withStyle`)
 
 -- | Add a 'Location' offset to the specified 'CursorLocation'.
 clOffset :: CursorLocation n -> Location -> CursorLocation n
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
@@ -4,6 +4,7 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
 -- | This module provides the core widget combinators and rendering
 -- routines. Everything this library does is in terms of these basic
 -- primitives.
@@ -485,6 +486,19 @@
 -- in the specified order (uppermost first). Defers growth policies to
 -- the growth policies of the contained widgets (if any are greedy, so
 -- is the box).
+--
+-- Allocates space to 'Fixed' elements first and 'Greedy' elements
+-- second. For example, if a 'vBox' contains three elements @A@, @B@,
+-- and @C@, and if @A@ and @B@ are 'Fixed', then 'vBox' first renders
+-- @A@ and @B@. Suppose those two take up 10 rows total, and the 'vBox'
+-- was given 50 rows. This means 'vBox' then allocates the remaining
+-- 40 rows to @C@. If, on the other hand, @A@ and @B@ take up 50 rows
+-- together, @C@ will not be rendered at all.
+--
+-- If all elements are 'Greedy', 'vBox' allocates the available height
+-- evenly among the elements. So, for example, if a 'vBox' is rendered
+-- in 90 rows and has three 'Greedy' elements, each element will be
+-- allocated 30 rows.
 {-# NOINLINE vBox #-}
 vBox :: [Widget n] -> Widget n
 vBox [] = emptyWidget
@@ -495,6 +509,19 @@
 -- in the specified order (leftmost first). Defers growth policies to
 -- the growth policies of the contained widgets (if any are greedy, so
 -- is the box).
+--
+-- Allocates space to 'Fixed' elements first and 'Greedy' elements
+-- second. For example, if an 'hBox' contains three elements @A@, @B@,
+-- and @C@, and if @A@ and @B@ are 'Fixed', then 'hBox' first renders
+-- @A@ and @B@. Suppose those two take up 10 columns total, and the
+-- 'hBox' was given 50 columns. This means 'hBox' then allocates the
+-- remaining 40 columns to @C@. If, on the other hand, @A@ and @B@ take
+-- up 50 columns together, @C@ will not be rendered at all.
+--
+-- If all elements are 'Greedy', 'hBox' allocates the available width
+-- evenly among the elements. So, for example, if an 'hBox' is rendered
+-- in 90 columns and has three 'Greedy' elements, each element will be
+-- allocated 30 columns.
 {-# NOINLINE hBox #-}
 hBox :: [Widget n] -> Widget n
 hBox [] = emptyWidget
@@ -809,9 +836,11 @@
 -- growth of otherwise-greedy widgets. This is non-greedy horizontally
 -- and defers to the limited widget vertically.
 hLimit :: Int -> Widget n -> Widget n
-hLimit w p =
-    Widget Fixed (vSize p) $
-      withReaderT (availWidthL %~ (min w)) $ render $ cropToContext p
+hLimit w p
+    | w <= 0 = emptyWidget
+    | otherwise =
+        Widget Fixed (vSize p) $
+          withReaderT (availWidthL %~ (min w)) $ render $ cropToContext p
 
 -- | Limit the space available to the specified widget to the specified
 -- percentage of available width, as a value between 0 and 100
@@ -820,22 +849,26 @@
 -- growth of otherwise-greedy widgets. This is non-greedy horizontally
 -- and defers to the limited widget vertically.
 hLimitPercent :: Int -> Widget n -> Widget n
-hLimitPercent w' p =
-    Widget Fixed (vSize p) $ do
-      let w = clamp 0 100 w'
-      ctx <- getContext
-      let usableWidth = ctx^.availWidthL
-          widgetWidth = round (toRational usableWidth * (toRational w / 100))
-      withReaderT (availWidthL %~ (min widgetWidth)) $ render $ cropToContext p
+hLimitPercent w' p
+    | w' <= 0 = emptyWidget
+    | otherwise =
+        Widget Fixed (vSize p) $ do
+          let w = clamp 0 100 w'
+          ctx <- getContext
+          let usableWidth = ctx^.availWidthL
+              widgetWidth = round (toRational usableWidth * (toRational w / 100))
+          withReaderT (availWidthL %~ (min widgetWidth)) $ render $ cropToContext p
 
 -- | Limit the space available to the specified widget to the specified
 -- number of rows. This is important for constraining the vertical
 -- growth of otherwise-greedy widgets. This is non-greedy vertically and
 -- defers to the limited widget horizontally.
 vLimit :: Int -> Widget n -> Widget n
-vLimit h p =
-    Widget (hSize p) Fixed $
-      withReaderT (availHeightL %~ (min h)) $ render $ cropToContext p
+vLimit h p
+    | h <= 0 = emptyWidget
+    | otherwise =
+        Widget (hSize p) Fixed $
+          withReaderT (availHeightL %~ (min h)) $ render $ cropToContext p
 
 -- | Limit the space available to the specified widget to the specified
 -- percentage of available height, as a value between 0 and 100
@@ -844,22 +877,26 @@
 -- growth of otherwise-greedy widgets. This is non-greedy vertically and
 -- defers to the limited widget horizontally.
 vLimitPercent :: Int -> Widget n -> Widget n
-vLimitPercent h' p =
-    Widget (hSize p) Fixed $ do
-      let h = clamp 0 100 h'
-      ctx <- getContext
-      let usableHeight = ctx^.availHeightL
-          widgetHeight = round (toRational usableHeight * (toRational h / 100))
-      withReaderT (availHeightL %~ (min widgetHeight)) $ render $ cropToContext p
+vLimitPercent h' p
+    | h' <= 0 = emptyWidget
+    | otherwise =
+        Widget (hSize p) Fixed $ do
+          let h = clamp 0 100 h'
+          ctx <- getContext
+          let usableHeight = ctx^.availHeightL
+              widgetHeight = round (toRational usableHeight * (toRational h / 100))
+          withReaderT (availHeightL %~ (min widgetHeight)) $ render $ cropToContext p
 
 -- | Set the rendering context height and width for this widget. This
 -- is useful for relaxing the rendering size constraints on e.g. layer
 -- widgets where cropping to the screen size is undesirable.
 setAvailableSize :: (Int, Int) -> Widget n -> Widget n
-setAvailableSize (w, h) p =
-    Widget Fixed Fixed $
-      withReaderT (\c -> c & availHeightL .~ h & availWidthL .~ w) $
-        render $ cropToContext p
+setAvailableSize (w, h) p
+    | w <= 0 || h <= 0 = emptyWidget
+    | otherwise =
+        Widget Fixed Fixed $
+          withReaderT (\c -> c & availHeightL .~ h & availWidthL .~ w) $
+            render $ cropToContext p
 
 -- | When drawing the specified widget, set the attribute used for
 -- drawing to the one with the specified name. Note that the widget may
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
@@ -188,7 +188,7 @@
 -- any edits applied here will be ignored if they edit text outside
 -- the line limit.
 applyEdit :: (Z.TextZipper t -> Z.TextZipper t)
-          -- ^ The 'Data.Text.Zipper' editing transformation to apply
+          -- ^ The 'Z.TextZipper' editing transformation to apply
           -> Editor t n
           -> Editor t n
 applyEdit f e = e & editContentsL %~ f
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
@@ -204,9 +204,9 @@
         _ -> return ()
 
 -- | Enable list movement with the vi keys with a fallback handler if
--- none match. Use 'handleListEventVi' 'handleListEvent' in place of
--- 'handleListEvent' to add the vi keys bindings to the standard ones.
--- Movements handled include:
+-- none match. Use 'handleListEventVi' in place of 'handleListEvent'
+-- to add the vi keys bindings to the standard ones. Movements handled
+-- include:
 --
 -- * Up (k)
 -- * Down (j)
