diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for brick-tabular-list
 
+## 2.0.0.0 -- 2023-03-13
+
+* Made it much easier to understand API and implementation
+* Improved documentation
+
 ## 1.0.0.1 -- 2023-03-10
 
 * Decreased lower version bound for base to allow hackage to build haddock documentation with ghc-9.2.4
diff --git a/brick-tabular-list.cabal b/brick-tabular-list.cabal
--- a/brick-tabular-list.cabal
+++ b/brick-tabular-list.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: brick-tabular-list
-version: 1.0.0.1
+version: 2.0.0.0
 
 synopsis: Tabular list widgets for brick.
 
diff --git a/demo/GridTabularList.hs b/demo/GridTabularList.hs
--- a/demo/GridTabularList.hs
+++ b/demo/GridTabularList.hs
@@ -96,7 +96,7 @@
          , "Press Ctrl+End or L to go to the last column"
          , "Press Ctrl+PageUp or Alt+h or Backspace to go left by one page of columns"
          , "Press Ctrl+PageDown or Alt+l to go right by one page of columns" ]
-  theList = renderGridTabularList (s ^. #libRenderers) True (s ^. #libList)
+  theList = renderGridTabularList (s ^. #libRenderers) (LstFcs True) (s ^. #libList)
   in [vCenter $ vBox $ hCenter (padLeftRight 2 $ joinBorders $ border $ hLimit (s ^. #listWidth) $ vLimit 15 theList)
                      : hCenter (str "Press Esc or q to exit" )
                      : hCenter (str "Press c to toggle column headers")
@@ -112,33 +112,33 @@
 colSelectedAttr :: AttrName
 colSelectedAttr = attrName "selectedColumn"
 
-colHdrs :: Vector String
-colHdrs = V.fromList ["Artist", "Title", "Album", "Composer", "Genre", "Time"]
-
 rowHdr :: RowHdr Name Song Int
 rowHdr = RowHdr {
-  draw = \_ wd f rh -> let
-    attrFn = if f
+  draw = \_ (WdthD wd) (RowHdrCtxt (Sel s)) r -> let
+    attrFn = if s
       then id
       else withAttr rowHdrAttr
-    in attrFn $ padRight (Pad $ if wd > 0 then 0 else 1) $ padLeft Max (str $ show rh)
-, width = \_ rh -> (+2) $ maximum $ map (length . show) rh
-, toRowHdr = \_ i -> i+1
+    in attrFn $ padRight (Pad $ if wd > 0 then 0 else 1) $ padLeft Max (str $ show r)
+, width = \_ rs -> RowHdrW $ (+2) $ maximum $ map (length . show) rs
+, toRH = \_ (Ix i) -> i+1
 }
 
+colHdrs :: Vector String
+colHdrs = V.fromList ["Artist", "Title", "Album", "Composer", "Genre", "Time"]
+
 colHdr :: GridColHdr Name
 colHdr = GridColHdr {
-  draw = \_ wd (FlatContext i _) -> let
+  draw = \_ (WdthD wd) (GColC (Ix ci) _) -> let
     renderColH = withAttr columnHdrAttr . padRight (Pad $ if wd > 0 then 0 else 1) . padRight Max . str
-    in case colHdrs V.!? i of
+    in case colHdrs V.!? ci of
       Just ch -> renderColH ch <=> hBorder
       Nothing -> emptyWidget
-, height = 2
+, height = ColHdrH 2
 }
 
 renderers :: LibraryRenderers
 renderers = GridRenderers {
-  drawCell = \_ wd (GridContext (FlatContext _ rs) (FlatContext ci cs)) s -> let
+  cell = \_ (WdthD wd) (GrdCtxt (GRowC _ (Sel rs)) (GColC (Ix ci) (Sel cs))) s -> let
     attrFn = if rs && cs
       then withAttr colSelectedAttr
       else id
@@ -157,11 +157,11 @@
       _ -> fill ' '
 , rowHdr = Just rowHdr
 , colHdr = Just colHdr
-, drawColHdrRowHdr = Just $ \_ _ -> vLimit 1 (fill ' ') <=> hBorder
+, colHdrRowHdr = CHRH $ \_ _ -> vLimit 1 (fill ' ') <=> hBorder
 }
 
 theList :: LibraryList
-theList = gridTabularList TheList songs 1 $ S.fromList [12, 11, 11, 14, 11, 7]
+theList = gridTabularList TheList songs (LstItmH 1) $ S.fromList $ fmap ColW [12, 11, 11, 14, 11, 7]
 
 main :: IO ()
 main = do
diff --git a/demo/MixedTabularList.hs b/demo/MixedTabularList.hs
--- a/demo/MixedTabularList.hs
+++ b/demo/MixedTabularList.hs
@@ -11,7 +11,7 @@
 import GHC.Generics (Generic)
 import Control.Monad (void)
 -- Third party libraries
-import Optics.Core
+import Optics.Core ( (^.) )
 import Data.Sequence (Seq)
 import qualified Data.Sequence as S
 import Data.Vector (Vector)
@@ -26,7 +26,7 @@
 import Brick.Util
 import Brick.Widgets.List
 import Brick.Widgets.Border.Style
-import Graphics.Vty (defAttr, Event(..), Key(..), Modifier(..), black, white, blue, red)
+import Graphics.Vty
 
 data Song = Song {
   artist :: String
@@ -40,8 +40,8 @@
 data Name = TheList deriving (Eq, Ord, Show)
 
 data Widths = Widths {
-  song :: [Width]
-, folder :: [Width]
+  song :: [ColWidth]
+, folder :: [ColWidth]
 } deriving Generic
 
 data AppState = AppState {
@@ -84,7 +84,7 @@
 
 drawUi :: AppState -> [Widget Name]
 drawUi s = let
-  theList = renderMixedTabularList (s ^. #libRenderers) True (s ^. #libList)
+  theList = renderMixedTabularList (s ^. #libRenderers) (LstFcs True) (s ^. #libList)
   msgs = [ "Press Up arrow or k to go up one item"
          , "Press Down arrow or j to go down one item"
          , "Press PageUp or Ctrl+b to go up one page"
@@ -106,8 +106,8 @@
 rowHdrAttr :: AttrName
 rowHdrAttr = attrName "rowHeader"
 
-dc :: ListFocused -> MixedContext -> LibraryEntry -> Widget n
-dc lf (MixedContext (FlatContext _ f) ci) e = let
+dc :: ListFocused -> MixedCtxt -> LibraryEntry -> Widget n
+dc _ (MxdCtxt _ (MColC (Ix ci))) e = let
   renderPlainCell s = padRight Max (str s) <+> str " "
   in case e of
     LibFolder f -> case ci of
@@ -127,48 +127,48 @@
 colHdrs :: Vector String
 colHdrs = V.fromList ["Artist", "Title", "Album", "Time"]
 
-cWprk :: AvailWidth -> [LibraryEntry] -> Widths
-cWprk aW _ = let
+wprk :: WidthsPerRowKind LibraryEntry Widths
+wprk = WsPerRK $ \(AvlW aW) _ -> let
   artist = max 7 $ (aW * 30) `div` 100
   title = max 6 $ (aW * 30) `div` 100
   time = 7
   album = aW - artist - title - time
-  in Widths { song = [artist, title, album, time], folder = [aW] }
+  in Widths { song = fmap ColW [artist, title, album, time], folder = [ColW aW] }
 
-wpr :: Widths -> LibraryEntry -> [Width]
-wpr (Widths {song, folder}) = \case
+wpr :: WidthsPerRow LibraryEntry Widths
+wpr = WsPerR $ \(Widths {song, folder}) e -> case e of
   LibSong _ -> song
   LibFolder _ -> folder
 
 rowHdr :: RowHdr Name LibraryEntry Int
 rowHdr = RowHdr {
-  draw = \lf wd f rh -> let
-    attrFn = if f
+  draw = \_ (WdthD wd) (RowHdrCtxt (Sel s)) rh -> let
+    attrFn = if s
       then id
       else withAttr rowHdrAttr
     in attrFn $ padRight (Pad $ if wd > 0 then 0 else 1) $ padLeft Max (str $ show rh)
-, width = \_ rh -> (+2) $ maximum $ map (length . show) rh
-, toRowHdr = \_ i -> i+1
+, width = \_ rh -> RowHdrW $ (+2) $ maximum $ map (length . show) rh
+, toRH = \_ (Ix i) -> i + 1
 }
 
 colHdr :: MixedColHdr Name Widths
 colHdr = MixedColHdr {
-  draw = \_ ci -> case colHdrs V.!? ci of
+  draw = \_ (MColC (Ix ci)) -> case colHdrs V.!? ci of
     Just ch -> withAttr columnHdrAttr (padRight Max (str ch) <+> str " ") <=> hBorder
     Nothing -> emptyWidget
 , widths = \Widths {song} -> song
-, height = 2
+, height = ColHdrH 2
 }
 
 main :: IO ()
 main = do
   let appState = AppState {
-        libList = mixedTabularList TheList libraryEntries 1 cWprk wpr
+        libList = mixedTabularList TheList libraryEntries (LstItmH 1) wprk wpr
       , libRenderers = MixedRenderers {
-          drawCell = dc
+          cell = dc
         , rowHdr = Just rowHdr
         , colHdr = Just colHdr
-        , drawColHdrRowHdr = Just $ \_ _ -> vLimit 1 (fill ' ') <=> hBorder
+        , colHdrRowHdr = CHRH $ \_ _ -> vLimit 1 (fill ' ') <=> hBorder
         }
       , listWidth = 80
       }
diff --git a/src/Brick/Widgets/TabularList.hs b/src/Brick/Widgets/TabularList.hs
--- a/src/Brick/Widgets/TabularList.hs
+++ b/src/Brick/Widgets/TabularList.hs
@@ -1,4 +1,4 @@
--- | This module contains only conceptual documentation.
+-- | Conceptual documentation
 module Brick.Widgets.TabularList where
 
 import Brick.Widgets.TabularList.Types
@@ -23,29 +23,38 @@
 -- Because tabular list widgets build on top of 'GenericList', attributes for 'GenericList' apply to tabular list
 -- widgets if the attributes are defined in your brick application.
 --
--- A rendering function for row columns or row headers is given a space with
+-- A rendering function for row headers is given a space with
 --
 -- @
--- 'setAvailableSize' (width, listItemHeight)
+-- 'setAvailableSize' (rowHeaderWidth, listItemHeight)
 -- @
 --
--- A rendering function for column headers or column header row header is given a space with
+-- A rendering function for row columns is given a space with
 --
 -- @
--- 'setAvailableSize' (width, columnHeaderHeight)
+-- 'setAvailableSize' (columnWidth, listItemHeight)
 -- @
 --
--- If the given height for rendering functions is not claimed, the list will look broken.
+-- A rendering function for column headers is given a space with
 --
--- The given width for rendering functions must be claimed by the returned widget with brick's padding functions or
--- 'hCenter'. Otherwise, the list will look broken.
+-- @
+-- 'setAvailableSize' (columnWidth, columnHeaderHeight)
+-- @
 --
--- 'WidthDeficit' is calculated for renderers of tabular list components that are shrunk to the available width.
+-- A rendering function for column header row header is given a space with
 --
+-- @
+-- 'setAvailableSize' (rowHeaderWidth, columnHeaderHeight)
+-- @
+--
+-- If the given height and the given width for rendering functions are not claimed, the list will look broken.
+--
+-- The given width for rendering functions should be claimed with brick's padding functions or 'hCenter'.
+--
 -- The following examples show how a rendering function can claim the available width.
 --
 -- @
--- 'padRight' ('Pad' $ if widthDeficit > 0 then 0 else 1) $ 'padLeft' 'Max' content
+-- 'padRight' ('Pad' 1) $ 'padLeft' 'Max' content
 -- @
 --
 -- @
@@ -53,9 +62,11 @@
 -- @
 --
 -- @
--- 'padLeft' ('Pad' $ if widthDeficit > 0 then 0 else 1) $ 'hCenter' content
+-- 'padLeft' ('Pad' 1) $ 'hCenter' content
 -- @
 --
--- In the examples above, I used padding with one space character at the left or the right to introduce gaps between
--- columns. If 'WidthDeficit' is positive, you may want to remove padding because a column is not followed or preceded
--- by other columns.
+-- In the examples above, I used fixed padding with one space character at the left or the right to introduce gaps
+-- between columns.
+--
+-- If there are fixed paddings used as gaps between columns, then 'WidthDeficit' should be used to remove gaps when the
+-- available width is narrower than the desired column width.
diff --git a/src/Brick/Widgets/TabularList/Grid.hs b/src/Brick/Widgets/TabularList/Grid.hs
--- a/src/Brick/Widgets/TabularList/Grid.hs
+++ b/src/Brick/Widgets/TabularList/Grid.hs
@@ -1,10 +1,11 @@
+{-# OPTIONS_HADDOCK show-extensions #-}
 {-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE OverloadedLabels #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NoFieldSelectors #-}
 {-# LANGUAGE NamedFieldPuns #-}
-{-# OPTIONS_HADDOCK show-extensions #-}
+{-# LANGUAGE TypeApplications #-}
 -- | Grid tabular list is a uniform grid that supports cell-by-cell navigation.
 --
 -- ![demo-01](grid-tabular-list-01.png) ![demo-02](grid-tabular-list-02.png) ![demo-03](grid-tabular-list-03.png)
@@ -18,10 +19,11 @@
 -- It should be fast enough to handle a large spreadsheet. It is also suitable for an interface to a database table.
 module Brick.Widgets.TabularList.Grid (
 -- * Data types
-  GridContext(..)
+  GridRowCtxt(..)
+, GridColCtxt(..)
+, GridCtxt(..)
 , GridColHdr(..)
 , GridRenderers(..)
-, GridWidths
 , GridTabularList(..)
 -- * List construction
 , gridTabularList
@@ -50,7 +52,7 @@
 import Data.Foldable (toList)
 import Control.Monad (unless)
 -- Third party libraries
-import Optics.Core ( (&), (%), (%~), (.~), (^.) )
+import Optics.Core ( (&), (%), (%~), (.~), (^.), coercedTo )
 import qualified Data.Sequence as S
 import Data.Sequence (Seq(..))
 import Data.Generics.Labels
@@ -61,19 +63,31 @@
 import Graphics.Vty (Event(..), Key(..), Modifier(..))
 import Brick.Main (lookupViewport)
 
+-- | Grid row context
+data GridRowCtxt = GRowC {
+  index :: Index
+, selected :: Selected
+} deriving (Eq, Generic, Show)
+
+-- | Grid column context
+data GridColCtxt = GColC {
+  index :: Index
+, selected :: Selected
+} deriving (Eq, Generic, Show)
+
 -- | Context for grid cells
-data GridContext = GridContext {
-  row :: FlatContext -- ^ Row context
-, col :: FlatContext -- ^ Column context
-} deriving (Show, Generic)
+data GridCtxt = GrdCtxt {
+  row :: GridRowCtxt
+, col :: GridColCtxt
+} deriving (Eq, Generic, Show)
 
 -- | Grid column header
 --
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 -- * [Rendering]("Brick.Widgets.TabularList#g:Rendering")
 data GridColHdr n = GridColHdr {
-  draw :: ListFocused -> WidthDeficit -> FlatContext -> Widget n
-, height :: Height -- ^ Height for column headers and column header row header
+  draw :: ListFocused -> WidthDeficit -> GridColCtxt -> Widget n
+, height :: ColHdrHeight
 } deriving Generic
 
 -- | Rendering functions for components of grid tabular list
@@ -81,20 +95,17 @@
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 -- * [Rendering]("Brick.Widgets.TabularList#g:Rendering")
 data GridRenderers n e r = GridRenderers {
-  drawCell :: ListFocused -> WidthDeficit -> GridContext -> e -> Widget n
+  cell :: ListFocused -> WidthDeficit -> GridCtxt -> e -> Widget n
 , rowHdr :: Maybe (RowHdr n e r)
 , colHdr :: Maybe (GridColHdr n)
-, drawColHdrRowHdr :: DrawColHdrRowHdr n
+, colHdrRowHdr :: ColHdrRowHdr n
 } deriving Generic
 
--- | Widths for column headers and row columns.
-type GridWidths = Seq Width
-
 -- | * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 data GridTabularList n e = GridTabularList {
   -- | The underlying primitive list that comes from brick
   list :: L.GenericList n Seq e
-, widths :: GridWidths
+, widths :: Seq ColWidth
   -- | Manipulating this field directly is unsafe. Use
   -- [column navigation]("Brick.Widgets.TabularList.Grid#g:ColumnNavigation") functions to manipulate this. If you still
   -- want to manipulate this directly, create a function that manipulates it, and test the function properly.
@@ -106,125 +117,132 @@
   :: n -- ^ The list name (must be unique)
   -> Seq e -- ^ The initial list elements
   -> ListItemHeight
-  -> GridWidths
+  -> Seq ColWidth
   -> GridTabularList n e
-gridTabularList n rows h widths = GridTabularList {
+gridTabularList n rows (LstItmH h) widths = GridTabularList {
   list = L.list n rows h
 , widths = widths
-, currentColumn = 0
+, currentColumn = Ix 0
 }
 
+-- | Width accumulated in the process of traversing columns
+newtype AccWidth = AccW Int deriving (Eq, Show)
+
 data VisibleColumns =
   -- | No column is visible
-  NoColumn
+  NoColumn |
   -- | Only current column is visible
-  | CurrentColumn
+  CurrentColumn |
   -- | The first column is shown at the left corner.
-  | AnchoredLeft {
-      right :: Int -- ^ The rightmost column that is visible
-  }
+  AnchoredLeft {
+      right :: Index -- ^ The rightmost column that is visible
+  } |
   -- | The current column is shown in the center
-  | MiddleColumns {
+  MiddleColumns {
     -- | The leftmost visible column
-    left :: Int,
+    left :: Index,
     -- | The rightmost visible column
-    right :: Int,
+    right :: Index,
     -- | Slide the columns to the left by this offset to show the current column in the center
     offset :: Int,
     -- | Total widths of all visible columns.
-    totalWidth :: Int
-  }
+    tW :: AccWidth
+  } |
   -- | The last column is shown at the right corner.
-  | AnchoredRight {
+  AnchoredRight {
     -- | The leftmost visible column
-    left :: Int,
+    left :: Index,
     -- | Slide the columns to the left by this offset to show the last column at the right corner.
     offset :: Int,
     -- | Total widths of all visible columns.
-    totalWidth :: Int
+    tW :: AccWidth
   }
-  deriving Show
+  deriving (Eq, Show)
 
 -- | Calculate visible columns with the width available for columns. It tries to show the current column in the center.
 -- If it can't show the current column in the center, the first column is shown at the left corner, or the last column
 -- is shown at the right corner.
 visibleColumns :: GridTabularList n e -> AvailWidth -> VisibleColumns
-visibleColumns l aW = let curCol = l ^. #currentColumn in
-  case S.splitAt curCol (l ^. #widths) of
+visibleColumns l (AvlW aW) = let
+  (Ix curCol) = l ^. #currentColumn
+  ws = l ^. #widths
+  in case S.splitAt curCol ws of
     -- If current column is outside the boundary of row columns, return `NoColumn`.
     (_, Empty) -> NoColumn
-    (left, cW :<| right) -> if aW <= 0
+    (left, ColW cW :<| right) -> if aW <= 0
       -- If the available width is 0 or less than 0,
       then NoColumn
-      -- If the available width is less than the current column's width,
-      else if cW >= aW
+      -- If the available width is equal to or less than the current column's width,
+      else if aW <= cW
       then CurrentColumn
-      -- Otherwise,
+      -- Otherwise
       else let
         -- The amount of space to the left of the current column shown in the center.
         lW = (aW - cW) `div` 2
         -- The amount of space to the right of the current column shown in the center.
         rW = aW - lW - cW
         -- Calculate the leftmost visible column for the current column shown in the center.
-        leftForMiddle (l :|> w) idx accW = if accW+w < lW
+        leftForMiddle (l :|> ColW w) (Ix idx) (AccW accW) = if accW+w < lW
           -- If the leftmost visible column hasn't been reached, go to the left by one column.
-          then leftForMiddle l (idx-1) (accW+w)
+          then leftForMiddle l (Ix $ idx-1) (AccW $ accW+w)
           -- If the leftmost visible column has been reached, calculate the rightmost visible column.
-          else rightForMiddle idx (accW+w) right (curCol+1) 0
+          else rightForMiddle (Ix idx) (AccW $ accW+w) right (Ix $ curCol + 1) (AccW 0)
         -- If there aren't enough columns to the left of the current column shown in the center, calculate the rightmost
         -- visible column for the first column shown at the left corner.
-        leftForMiddle Empty _ accW = rightForLeft right (curCol+1) (accW+cW)
+        leftForMiddle Empty _ (AccW accW) = rightForLeft right (Ix $ curCol+1) (AccW $ accW+cW)
         -- Calculate the rightmost visible column for the current column shown in the center.
-        rightForMiddle li lAccW (w :<| r) ri accW = if accW+w < rW
+        rightForMiddle (Ix li) (AccW lAccW) (ColW w :<| r) (Ix ri) (AccW accW) = if accW+w < rW
           -- If the rightmost visible column hasn't been reached, go to the right by one column.
-          then rightForMiddle li lAccW r (ri+1) (accW+w)
+          then rightForMiddle (Ix li) (AccW lAccW) r (Ix $ ri+1) (AccW $ accW+w)
           -- If the rightmost visible column has been reached, return 'MiddleColumns'.
-          else MiddleColumns { left = li, right = ri, offset = lAccW-lW, totalWidth = lAccW+cW+accW+w }
+          else MiddleColumns { left = Ix li, right = Ix ri, offset = lAccW-lW, tW = AccW $ lAccW+cW+accW+w }
         -- If there aren't enough columns to the right of the current column shown in the center, calculate the leftmost
         -- visible column for the last column shown at the right corner.
-        rightForMiddle _ _ Empty _ accW = leftForRight left (curCol-1) (accW+cW)
+        rightForMiddle _ _ Empty _ (AccW accW) = leftForRight left (Ix $ curCol-1) (AccW $ accW+cW)
         -- Calculate the rightmost visible column for the first column shown at the left corner.
-        rightForLeft (w :<| r) idx accW = if accW+w < aW
+        rightForLeft (ColW w :<| r) (Ix idx) (AccW accW) = if accW+w < aW
           -- If the rightmost visible column hasn't been reached, go to the right by one column.
-          then rightForLeft r (idx+1) (accW+w)
+          then rightForLeft r (Ix $ idx+1) (AccW $ accW+w)
           -- If the rightmost visible column has been reached, return 'AnchoredLeft'.
-          else AnchoredLeft idx
+          else AnchoredLeft $ Ix idx
         -- If there aren't enough columns to fill the available width with the first column at the left corner, return
         -- 'AnchoredLeft' with the last column as the rightmost visible column.
-        rightForLeft Empty idx _ = AnchoredLeft (idx-1)
+        rightForLeft Empty (Ix idx) _ = AnchoredLeft (Ix $ idx-1)
         -- Calculate the leftmost visible column for the last column shown at the right corner.
-        leftForRight (l :|> w) idx accW = if accW+w < aW
+        leftForRight (l :|> ColW w) (Ix idx) (AccW accW) = if accW+w < aW
           -- If the leftmost visible column hasn't been reached, go to the left by one column.
-          then leftForRight l (idx-1) (accW+w)
+          then leftForRight l (Ix $ idx-1) (AccW $ accW+w)
           -- If the leftmost visible column has been reached, return 'AnchoredRight'.
-          else AnchoredRight { left = idx, offset = accW+w-aW, totalWidth = accW+w }
+          else AnchoredRight { left = Ix idx, offset = accW+w-aW, tW = AccW $ accW+w }
         -- If there aren't enough columns to fill the available width with the last column at the right corner, return
         -- 'AnchoredLeft' with the last column as the rightmost visible column.
-        leftForRight Empty _ _ = AnchoredLeft $ length (l ^. #widths) - 1
-        -- Calculate the leftmost visible column for the current column shown in the center.
-        in leftForMiddle left (curCol-1) 0
+        leftForRight Empty _ _ = AnchoredLeft $ Ix $ length ws - 1
+        in leftForMiddle left (Ix $ curCol-1) (AccW 0)
 
+-- | Height for tabular list components
+newtype Height = H Int deriving (Eq, Show)
+
 renderColumns
   :: GridTabularList n e
   -> VisibleColumns
-  -> (WidthDeficit -> Index -> Width -> Widget n)
+  -> (WidthDeficit -> Index -> ColWidth -> Widget n)
   -> Height
   -> Widget n
-renderColumns l vCs dC h = Widget Greedy Fixed $ do
+renderColumns l vCs dC (H h) = Widget Greedy Fixed $ do
   c <- getContext
   let cWs = l ^. #widths
-      curCol = l ^. #currentColumn
+      Ix curCol = l ^. #currentColumn
       aW = c^^.availWidthL
   render $ case vCs of
     NoColumn -> emptyWidget
     CurrentColumn -> case S.lookup curCol cWs of
       Nothing -> error $ "Current column, " <> show curCol <> " is outside the boundary of column widths."
-      Just cW -> dC (max 0 $ cW - aW) curCol aW
-    AnchoredLeft right -> hBox $ zipWith (dC 0) [0..] $ toList $ S.take (right+1) cWs
-    MiddleColumns {left, right, offset, totalWidth} -> cropLeftBy offset $ setAvailableSize (totalWidth, h) $
-      hBox $ zipWith (dC 0) [left..] $ toList $ S.take (right-left+1) $ S.drop left cWs
-    AnchoredRight {left, offset, totalWidth} -> cropLeftBy offset $ setAvailableSize (totalWidth, h) $
-      hBox $ zipWith (dC 0) [left..] $ toList $ S.drop left cWs
+      Just (ColW cW) -> dC (WdthD $ max 0 $ cW - aW) (Ix curCol) (ColW aW)
+    AnchoredLeft {right=Ix r} -> hBox $ zipWith (dC $ WdthD 0) [Ix 0..] $ toList $ S.take (r+1) cWs
+    MiddleColumns {left=Ix l, right=Ix r, offset, tW=AccW tw} -> cropLeftBy offset $ sz (tw, h) $
+      hBox $ zipWith (dC $ WdthD 0) [Ix l..] $ toList $ S.take (r-l+1) $ S.drop l cWs
+    AnchoredRight {left=Ix l, offset, tW=AccW tw} -> cropLeftBy offset $ sz (tw, h) $
+      hBox $ zipWith (dC $ WdthD 0) [Ix l..] $ toList $ S.drop l cWs
 
 -- | Render grid tabular list
 renderGridTabularList :: (Ord n, Show n)
@@ -232,35 +250,35 @@
   -> ListFocused
   -> GridTabularList n e -- ^ The list
   -> Widget n
-renderGridTabularList r lf l = Widget Greedy Greedy $ do
+renderGridTabularList r (LstFcs f) l = Widget Greedy Greedy $ do
   c <- getContext
   let aW = c^^.availWidthL
       aH = c^^.availHeightL
-      GridRenderers {drawCell} = r
+      cell = r ^. #cell
       GridTabularList {list=l', currentColumn=curCol} = l
       iH = l' ^. #listItemHeight
-      colHdrRow vCs rhw' rhwd = case r ^. #colHdr of
+      colHdrRow vCs (RowHdrW rhw) (WdthD rhwd) = case r ^. #colHdr of
         Nothing -> emptyWidget
-        Just (GridColHdr {draw, height}) -> let
-          drawCol wd c w = setAvailableSize (w, height) $ draw lf wd (FlatContext c (c == curCol))
-          chrw = case r ^. #drawColHdrRowHdr of
-            Nothing -> fill ' '
-            Just dchrw -> dchrw lf rhwd
-          in setAvailableSize (rhw', height) chrw <+> renderColumns l vCs drawCol height
-      renderRow vCs i f r = let
-        drawCol wd c w = let gc = GridContext (FlatContext i f) (FlatContext c $ c == curCol)
-          in setAvailableSize (w, iH) $ drawCell lf wd gc r
-        in renderColumns l vCs drawCol iH
-      renderList = let vCs = visibleColumns l aW in
-        render $ colHdrRow vCs 0 0 <=> L.renderListWithIndex (renderRow vCs) lf l'
-      renderHdrList (RowHdr {draw, width, toRowHdr}) = let
-        rhw = width aW $ zipWithVisibleRowsAndIndexes l' aH toRowHdr
-        rhw' = min rhw aW
-        rhwd = max 0 $ rhw - aW
-        vCs = visibleColumns l $ aW - rhw'
-        renderHdrRow i f r = setAvailableSize (rhw', iH) (draw lf rhwd f $ toRowHdr r i) <+> renderRow vCs i f r
-        in render $ colHdrRow vCs rhw' rhwd <=> L.renderListWithIndex renderHdrRow lf l'
-  maybe renderList renderHdrList $ r ^. #rowHdr
+        Just (GridColHdr {draw, height=ColHdrH chh}) -> let
+          drawCol wd c (ColW w) = sz (w, chh) $ draw (LstFcs f) wd $ GColC c $ Sel (c == curCol)
+          chrw = case r ^. #colHdrRowHdr of
+            BlankCHRH -> fill ' '
+            CHRH dchrw -> dchrw (LstFcs f) (WdthD rhwd)
+          in sz (rhw, chh) chrw <+> renderColumns l vCs drawCol (H chh)
+      row vCs i f r = let
+        col wd c (ColW w) = let gc = GrdCtxt (GRowC (Ix i) (Sel f)) $ GColC c $ Sel (c == curCol)
+          in sz (w, iH) $ cell (LstFcs f) wd gc r
+        in renderColumns l vCs col (H iH)
+      drawList = let vCs = visibleColumns l (AvlW aW) in
+        render $ colHdrRow vCs (RowHdrW 0) (WdthD 0) <=> L.renderListWithIndex (row vCs) f l'
+      drawHdrList (RowHdr {draw, width, toRH}) = let
+        RowHdrW rhw' = width (AvlW aW) $ uncurry (zipWith toRH) $ visibleRowIdx l' (AvlH aH)
+        rhw = min rhw' aW
+        rhwd = WdthD $ max 0 $ rhw' - aW
+        vCs = visibleColumns l $ AvlW $ aW - rhw
+        hdrRow i f r = sz (rhw, iH) (draw (LstFcs f) rhwd (RowHdrCtxt $ Sel f) $ toRH r (Ix i)) <+> row vCs i f r
+        in render $ colHdrRow vCs (RowHdrW rhw) rhwd <=> L.renderListWithIndex hdrRow f l'
+  maybe drawList drawHdrList $ r ^. #rowHdr
 
 -- | Move to the left by one column.
 gridMoveLeft
@@ -268,7 +286,7 @@
   -> GridTabularList n e
 gridMoveLeft gl = if null $ gl ^. #list % #listSelected
   then gl
-  else gl & #currentColumn %~ max 0 . subtract 1
+  else gl & #currentColumn % coercedTo @Int %~ max 0 . subtract 1
 
 -- | Move to the right by one column.
 gridMoveRight
@@ -276,16 +294,16 @@
   -> GridTabularList n e
 gridMoveRight gl = if null $ gl ^. #list % #listSelected
   then gl
-  else gl & #currentColumn %~ min (length (gl ^. #widths) - 1) . (+1)
+  else gl & #currentColumn % coercedTo @Int %~ min (length (gl ^. #widths) - 1) . (+1)
 
 -- | Move to the given column index
 gridMoveTo
   :: Index
   -> GridTabularList n e -- ^ The list
   -> GridTabularList n e
-gridMoveTo n gl = if null $ gl ^. #list % #listSelected
+gridMoveTo (Ix n) gl = if null $ gl ^. #list % #listSelected
   then gl
-  else gl & #currentColumn .~ (max 0 . min (length (gl ^. #widths) - 1)) n
+  else gl & #currentColumn % coercedTo @Int .~ max 0 (min (length (gl ^. #widths) - 1) n)
 
 -- | Move to the first column.
 gridMoveToBeginning
@@ -293,7 +311,7 @@
   -> GridTabularList n e
 gridMoveToBeginning gl = if null $ gl ^. #list % #listSelected
   then gl
-  else gl & #currentColumn .~ 0
+  else gl & #currentColumn % coercedTo @Int .~ 0
 
 -- | Move to the last column.
 gridMoveToEnd
@@ -301,7 +319,7 @@
   -> GridTabularList n e
 gridMoveToEnd gl = if null $ gl ^. #list % #listSelected
   then gl
-  else gl & #currentColumn .~ length (gl ^. #widths) - 1
+  else gl & #currentColumn % coercedTo @Int .~ length (gl ^. #widths) - 1
 
 -- | 'GridRenderers' are needed because if row header renderer doesn't exist, width calculation is affected.
 gridMovePage :: Ord n
@@ -310,16 +328,17 @@
   -> EventM n (GridTabularList n e) ()
 gridMovePage r f = do
   l <- get
-  unless (null $ l ^. #list % #listSelected) $ do
-    v <- lookupViewport $ l ^. #list % #listName
+  let l' = l ^. #list
+  unless (null $ l' ^^. L.listSelectedL) $ do
+    v <- lookupViewport $ l' ^^. L.listNameL
     case v of
       Nothing -> return ()
       Just vp -> let
         (aW, aH) = vp ^. #_vpSize
-        rhw = case r ^. #rowHdr of
-          Nothing -> 0
-          Just (RowHdr {width, toRowHdr}) -> width aW $ zipWithVisibleRowsAndIndexes (l ^. #list) aH toRowHdr
-        in f $ visibleColumns l $ aW - rhw
+        RowHdrW rhw = case r ^. #rowHdr of
+          Nothing -> RowHdrW 0
+          Just (RowHdr {width, toRH}) -> width (AvlW aW) $ uncurry (zipWith toRH) $ visibleRowIdx l' (AvlH aH)
+        in f $ visibleColumns l $ AvlW $ aW - rhw
 
 -- | Move to the previous page of columns.
 --
diff --git a/src/Brick/Widgets/TabularList/Internal/Common.hs b/src/Brick/Widgets/TabularList/Internal/Common.hs
--- a/src/Brick/Widgets/TabularList/Internal/Common.hs
+++ b/src/Brick/Widgets/TabularList/Internal/Common.hs
@@ -1,8 +1,7 @@
 module Brick.Widgets.TabularList.Internal.Common (
-  AvailHeight
-, visibleRowsWithStart
-, visibleRows
-, zipWithVisibleRowsAndIndexes
+  AvailHeight(..)
+, visibleRowIdx
+, sz
 ) where
 
 import Brick.Widgets.TabularList.Types
@@ -14,27 +13,28 @@
 import Data.Sequence (Seq)
 -- Brick
 import Brick.Widgets.List
+import Brick.Types
+import Brick.Widgets.Core
 
 -- | Height available for 'GenericList'
-type AvailHeight = Int
+newtype AvailHeight = AvlH Int deriving (Show, Eq)
 
--- | Return visible rows and the index of the first visible row, given 'GenericList' and height available for list.
-visibleRowsWithStart :: GenericList n Seq row -> AvailHeight -> ([row], Index)
-visibleRowsWithStart l aH = let
+-- | Return visible rows and their row indexes.
+--
+-- The visible rows are rows that are visible when the current row is either at the top or the bottom.
+visibleRowIdx :: GenericList n Seq e -> AvailHeight -> ([e], [Index])
+visibleRowIdx l (AvlH h) = let
   idx = fromMaybe 0 (l^.listSelectedL)
-  numPerHeight = case aH `divMod` (l^.listItemHeightL) of
+  numPerHeight = case h `divMod` (l^.listItemHeightL) of
     (nph, 0) -> nph
     (nph, _) -> nph + 1
+  -- If the current row is at the bottom, the start should be visible.
   start = max 0 $ idx - numPerHeight + 1
+  -- If the current row is at the top, the row at start + length - 1 should be visible.
   length = numPerHeight * 2
   rows = toList $ slice start length $ l^.listElementsL
-  in (rows, start)
-
--- | Return visible rows, given 'GenericList' and height available for list.
-visibleRows :: GenericList n Seq e -> AvailHeight -> [e]
-visibleRows l aH = fst $ visibleRowsWithStart l aH
+  in (rows, [Ix start..])
 
--- | Zip visible rows and their row indexes with a function.
-zipWithVisibleRowsAndIndexes :: GenericList n Seq e -> AvailHeight -> (e -> Index -> c) -> [c]
-zipWithVisibleRowsAndIndexes l aH f = let (es, s) = visibleRowsWithStart l aH
-  in zipWith f es [s..]
+-- | It is a shortened version of 'setAvailableSize'.
+sz :: (Int, Int) -> Widget n -> Widget n
+sz (w, h) = if w <= 0 then const emptyWidget else setAvailableSize (w, h)
diff --git a/src/Brick/Widgets/TabularList/Internal/Lens.hs b/src/Brick/Widgets/TabularList/Internal/Lens.hs
--- a/src/Brick/Widgets/TabularList/Internal/Lens.hs
+++ b/src/Brick/Widgets/TabularList/Internal/Lens.hs
@@ -1,6 +1,6 @@
 -- | Alternate operators for microlens.
 --
--- Since optic operators take precedence, microlens operators need to be given alternate names.
+-- Since optic operators take precedence in this library, microlens operators need to be given alternate names.
 module Brick.Widgets.TabularList.Internal.Lens (
   (^^.)
 ) where
diff --git a/src/Brick/Widgets/TabularList/Mixed.hs b/src/Brick/Widgets/TabularList/Mixed.hs
--- a/src/Brick/Widgets/TabularList/Mixed.hs
+++ b/src/Brick/Widgets/TabularList/Mixed.hs
@@ -1,9 +1,9 @@
+{-# OPTIONS_HADDOCK show-extensions #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE OverloadedLabels #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE NoFieldSelectors #-}
-{-# OPTIONS_HADDOCK show-extensions #-}
 -- | Mixed tabular list is a list with different kinds of rows.
 --
 -- ![demo](mixed-tabular-list.png)
@@ -17,11 +17,13 @@
 -- Because this list is designed to show every column in the available space, horizontal scrolling is not supported.
 module Brick.Widgets.TabularList.Mixed (
 -- * Data types
-  MixedContext(..)
+  MixedRowCtxt(..)
+, MixedColCtxt(..)
+, MixedCtxt(..)
 , MixedColHdr(..)
 , MixedRenderers(..)
-, CalcWidthsPerRowKind
-, WidthsPerRow
+, WidthsPerRowKind(..)
+, WidthsPerRow(..)
 , MixedTabularList(..)
 -- * List construction
 , mixedTabularList
@@ -52,21 +54,30 @@
 import Brick.Widgets.Core
 import Graphics.Vty.Input.Events (Event)
 
+-- | Mixed row context
+data MixedRowCtxt = MRowC {
+  index :: Index
+, selected :: Selected
+} deriving (Eq, Generic, Show)
+
+-- | Mixed column context
+newtype MixedColCtxt = MColC { index :: Index } deriving (Eq, Generic, Show)
+
 -- | Context for mixed columns
-data MixedContext = MixedContext {
-  row :: FlatContext -- ^ Row context
-, col :: Index -- ^ Index of column
-}
+data MixedCtxt = MxdCtxt {
+  row :: MixedRowCtxt
+, col :: MixedColCtxt
+} deriving (Eq, Generic, Show)
 
 -- | Mixed column header
 --
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 -- * [Rendering]("Brick.Widgets.TabularList#g:Rendering")
 data MixedColHdr n w = MixedColHdr {
-  draw :: ListFocused -> Index -> Widget n
+  draw :: ListFocused -> MixedColCtxt -> Widget n
   -- | A function for getting widths for column headers from the type that contains widths per row kind
-, widths :: w -> [Width]
-, height:: Height -- ^ Height for column headers and column header row header
+, widths :: w -> [ColWidth]
+, height :: ColHdrHeight
 } deriving Generic
 
 -- | Rendering functions for components of mixed tabular list
@@ -74,27 +85,27 @@
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 -- * [Rendering]("Brick.Widgets.TabularList#g:Rendering")
 data MixedRenderers n e w r = MixedRenderers {
-  drawCell :: ListFocused -> MixedContext -> e -> Widget n
+  cell :: ListFocused -> MixedCtxt -> e -> Widget n
 , rowHdr :: Maybe (RowHdr n e r)
 , colHdr :: Maybe (MixedColHdr n w)
-, drawColHdrRowHdr :: DrawColHdrRowHdr n
+, colHdrRowHdr :: ColHdrRowHdr n
 } deriving Generic
 
 -- | Calculate widths per row kind from visible list rows and the width available after row header.
 --
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
-type CalcWidthsPerRowKind e w = AvailWidth -> [e] -> w
+newtype WidthsPerRowKind e w = WsPerRK (AvailWidth -> [e] -> w) deriving Generic
 
 -- | It is a function to get widths for each row. Use pattern matching to detect the kind of each row. Usually, a row
 -- kind is a data constructor of row data type.
 --
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
-type WidthsPerRow e w = w -> e -> [Width]
+newtype WidthsPerRow e w = WsPerR (w -> e -> [ColWidth]) deriving Generic
 
 -- | * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 data MixedTabularList n e w = MixedTabularList {
   list :: L.GenericList n Seq e -- ^ The underlying list that comes from brick
-, calcWidthsPerRowKind :: CalcWidthsPerRowKind e w
+, widthsPerRowKind :: WidthsPerRowKind e w
 , widthsPerRow :: WidthsPerRow e w
 } deriving Generic
 
@@ -102,12 +113,12 @@
 mixedTabularList :: n -- ^ The name of the list. It must be unique.
   -> Seq e -- ^ The initial list elements
   -> ListItemHeight
-  -> CalcWidthsPerRowKind e w
+  -> WidthsPerRowKind e w
   -> WidthsPerRow e w
   -> MixedTabularList n e w
-mixedTabularList n rows h cWprk wpr = MixedTabularList {
+mixedTabularList n rows (LstItmH h) wprk wpr = MixedTabularList {
   list = L.list n rows h
-, calcWidthsPerRowKind = cWprk
+, widthsPerRowKind = wprk
 , widthsPerRow = wpr
 }
 
@@ -117,35 +128,35 @@
   -> ListFocused
   -> MixedTabularList n e w -- ^ The list
   -> Widget n
-renderMixedTabularList r lf l = Widget Greedy Greedy $ do
+renderMixedTabularList r (LstFcs f) l = Widget Greedy Greedy $ do
   c <- getContext
   let aW = c^^.availWidthL
       aH = c^^.availHeightL
-      MixedRenderers {drawCell} = r
-      MixedTabularList {list=l', calcWidthsPerRowKind=cWprk, widthsPerRow=wpr} = l
+      cell = r ^. #cell
+      MixedTabularList {list=l', widthsPerRowKind=WsPerRK wprk', widthsPerRow=WsPerR wpr} = l
       iH = l' ^^. L.listItemHeightL
-      colHdrRow wprk rhw' rhwd = case r ^. #colHdr of
+      colHdrRow wprk (RowHdrW rhw) (WdthD rhwd) = case r ^. #colHdr of
         Nothing -> emptyWidget
-        Just (MixedColHdr {draw, widths, height}) -> let
-          drawCol ci w = setAvailableSize (w, height) $ draw lf ci
-          chrw = case r ^. #drawColHdrRowHdr of
-            Nothing -> fill ' '
-            Just dchrw -> dchrw lf rhwd
-          in setAvailableSize (rhw', height) chrw <+> hBox (zipWith drawCol [0..] $ widths wprk)
-      renderRow wprk i f row = let
-        drawColumn ci w = setAvailableSize (w, iH) $ drawCell lf (MixedContext (FlatContext i f) ci) row
-        in hBox $ zipWith drawColumn [0..] $ wpr wprk row
-      renderList = let wprk = cWprk aW $ visibleRows l' aH
-        in render $ colHdrRow wprk 0 0 <=> L.renderListWithIndex (renderRow wprk) lf l'
-      renderHdrList (RowHdr {draw, width, toRowHdr}) = let
-        (es, s) = visibleRowsWithStart l' aH
-        rhw = width aW $ zipWith toRowHdr es [s..]
-        rhw' = min rhw aW
-        rhwd = max 0 $ rhw - aW
-        wprk = cWprk (aW - rhw') es
-        renderHdrRow i f r = setAvailableSize (rhw', iH) (draw lf rhwd f $ toRowHdr r i) <+> renderRow wprk i f r
-        in render $ colHdrRow wprk rhw' rhwd <=> L.renderListWithIndex renderHdrRow lf l'
-  maybe renderList renderHdrList $ r ^. #rowHdr
+        Just (MixedColHdr {draw, widths, height=ColHdrH chh}) -> let
+          drawCol ci (ColW w) = sz (w, chh) $ draw (LstFcs f) (MColC ci)
+          chrw = case r ^. #colHdrRowHdr of
+            BlankCHRH -> fill ' '
+            CHRH chrw -> chrw (LstFcs f) (WdthD rhwd)
+          in sz (rhw, chh) chrw <+> hBox (zipWith drawCol [Ix 0..] $ widths wprk)
+      row wprk i f r = let
+        col ci (ColW w) = sz (w, iH) $ cell (LstFcs f) (MxdCtxt (MRowC (Ix i) (Sel f)) $ MColC ci) r
+        in hBox $ zipWith col [Ix 0..] $ wpr wprk r
+      drawList = let wprk = wprk' (AvlW aW) $ fst $ visibleRowIdx l' (AvlH aH)
+        in render $ colHdrRow wprk (RowHdrW 0) (WdthD 0) <=> L.renderListWithIndex (row wprk) f l'
+      drawHdrList (RowHdr {draw, width, toRH}) = let
+        (es, is) = visibleRowIdx l' (AvlH aH)
+        RowHdrW rhw' = width (AvlW aW) $ zipWith toRH es is
+        rhw = min rhw' aW
+        rhwd = WdthD $ max 0 $ rhw' - aW
+        wprk = wprk' (AvlW $ aW - rhw) es
+        hdrRow i f r = sz (rhw, iH) (draw (LstFcs f) rhwd (RowHdrCtxt $ Sel f) $ toRH r (Ix i)) <+> row wprk i f r
+        in render $ colHdrRow wprk (RowHdrW rhw) rhwd <=> L.renderListWithIndex hdrRow f l'
+  maybe drawList drawHdrList $ r ^. #rowHdr
 
 -- | Handle events for mixed tabular list with navigation keys. This just calls 'L.handleListEvent'.
 handleMixedListEvent :: Ord n
diff --git a/src/Brick/Widgets/TabularList/Types.hs b/src/Brick/Widgets/TabularList/Types.hs
--- a/src/Brick/Widgets/TabularList/Types.hs
+++ b/src/Brick/Widgets/TabularList/Types.hs
@@ -1,79 +1,96 @@
+{-# OPTIONS_HADDOCK show-extensions #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE NoFieldSelectors #-}
-{-# OPTIONS_HADDOCK show-extensions #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 -- | Types shared by tabular list widgets.
 --
 -- You don't have to import this module because modules for tabular list widgets re-export this module.
 module Brick.Widgets.TabularList.Types (
-  Index
-, Width
-, Height
-, AvailWidth
-, ListItemHeight
-, FlatContext(..)
-, WidthDeficit
-, ListFocused
-, Selected
+-- * Tabular dimensions
+  RowHdrWidth(..)
+, ColWidth(..)
+, ColHdrHeight(..)
+, ListItemHeight(..)
+-- * Shared rendering context
+, Index(..)
+, AvailWidth(..)
+, WidthDeficit(..)
+, ListFocused(..)
+, Selected(..)
+-- * Row header
+, RowHdrCtxt(..)
 , RowHdr(..)
-, DrawColHdrRowHdr
+, ColHdrRowHdr(..)
 ) where
 
 -- base
 import GHC.Generics (Generic)
 -- brick
 import Brick.Types
+import Brick.Widgets.Center
+import Brick.Widgets.Core
 
 -- | Index of a tabular list component among the same kind of components
-type Index = Int
+newtype Index = Ix Int deriving (Enum, Eq, Generic, Show)
 
--- | Width of a tabular list component
-type Width = Int
+-- | Width for row header
+newtype RowHdrWidth = RowHdrW Int deriving (Eq, Generic, Show)
 
--- | Height of a tabular list component
-type Height = Int
+-- | Width of a column header or a row column
+newtype ColWidth = ColW Int deriving (Eq, Generic, Show)
 
--- | Available width
-type AvailWidth = Int
+-- | Height for column headers and column header row header
+newtype ColHdrHeight = ColHdrH Int deriving (Eq, Generic, Show)
 
 -- | The fixed height for row headers and row columns.
 --
 -- If the height of row headers or row columns is not this height, then the list will look broken.
-type ListItemHeight = Int
+newtype ListItemHeight = LstItmH Int deriving (Eq, Generic, Show)
 
--- | Context for one dimensional tabular list components
-data FlatContext = FlatContext {
-  index :: Index -- ^ Index of a component
-, selected :: Bool -- ^ Whether a component is selected
-} deriving (Show, Generic)
+-- | Available width
+newtype AvailWidth = AvlW Int deriving (Eq, Generic, Show)
 
--- | > widthDeficit = max 0 $ desiredWidth - availableWidth
+-- | > widthDeficit = max 0 $ desiredColumnWidth - availableWidth
 --
 -- It is positive when a column is shrunk to the available width.
 --
--- If it is positive, you may want to remove paddings in your content because it is not followed or preceded by
--- other columns.
-type WidthDeficit = Int
+-- If you use fixed paddings to introduce gaps between columns, you may want to remove fixed paddings when width deficit
+-- is positive because a column is not preceded or followed by other columns and its width is shrunk.
+--
+-- The following examples show how to remove gaps between columns when width deficit is positive.
+--
+-- @
+-- 'padRight' ('Pad' $ if widthDeficit > 0 then 0 else 1) $ 'padLeft' 'Max' content
+-- @
+--
+-- @
+-- 'padLeft' ('Pad' $ if widthDeficit > 0 then 0 else 1) $ 'hCenter' content
+-- @
+newtype WidthDeficit = WdthD Int deriving (Eq, Generic, Show)
 
 -- | Whether the list is focused in an application
-type ListFocused = Bool
+newtype ListFocused = LstFcs Bool deriving (Eq, Generic, Show)
 
 -- | Whether a tabular list component is selected
-type Selected = Bool
+newtype Selected = Sel Bool deriving (Eq, Generic, Show)
 
+-- | Row header context
+newtype RowHdrCtxt = RowHdrCtxt Selected deriving (Eq, Generic, Show)
+
 -- | Row header
 --
 -- * [Type Variables]("Brick.Widgets.TabularList#g:TypeVariables")
 -- * [Rendering]("Brick.Widgets.TabularList#g:Rendering")
 data RowHdr n e r = RowHdr {
-  draw :: ListFocused -> WidthDeficit -> Selected -> r -> Widget n
+  draw :: ListFocused -> WidthDeficit -> RowHdrCtxt -> r -> Widget n
   -- | Calculate row header width from visible row headers and the width available for a list row.
-, width :: AvailWidth -> [r] -> Width
+, width :: AvailWidth -> [r] -> RowHdrWidth
   -- | Get a row header from a list row and row index.
-, toRowHdr :: e -> Index -> r
+, toRH :: e -> Index -> r
 } deriving Generic
 
 -- | The renderer for column header row header.
 --
--- If row headers and column headers exist and 'DrawColHdrRowHdr' is 'Nothing', then column header row header is
--- filled with empty space. 'DrawColHdrRowHdr' merely allows you to customize column header row header.
-type DrawColHdrRowHdr n = Maybe (ListFocused -> WidthDeficit -> Widget n)
+-- If row headers and column headers exist and 'ColHdrRowHdr' is 'BlankCHRH', then column header row header is
+-- filled with empty space. 'ColHdrRowHdr' merely allows you to customize column header row header.
+data ColHdrRowHdr n = BlankCHRH | CHRH (ListFocused -> WidthDeficit -> Widget n) deriving Generic
