diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 Series 1
 ---------
 
+ * 1.2.5.0  -- enable widget caching and invalidation with Ctrl-R invalidate all
  * 1.2.4.1  -- documentation updates; separate changelog file.
  * 1.2.4.0  -- added brick 0.17 compatibility
  * 1.2.3.0  -- added brick 0.16 compatibility
diff --git a/examples/bookcase.hs b/examples/bookcase.hs
--- a/examples/bookcase.hs
+++ b/examples/bookcase.hs
@@ -110,7 +110,7 @@
 
 
 setBooks :: ItemState -> e -> ItemFieldWidget n -> EventM n (ItemFieldWidget n)
-setBooks toState _ fieldw = return $ setMarkedItemsState toState fieldw
+setBooks toState _ fieldw = setMarkedItemsState toState fieldw
 
 
 main :: IO ()
diff --git a/examples/workreport.hs b/examples/workreport.hs
--- a/examples/workreport.hs
+++ b/examples/workreport.hs
@@ -52,6 +52,7 @@
                 , ItemGroup "Team 5" $ Items 0
                 , ItemGroup "Team 6" $ Items 3
                 ]
+        -- teams = []  -- alternative: no workers, not very interesting
     in WorkerTeams (ItemFieldWidget n $ newItemField teams Nothing)
 
 
@@ -143,9 +144,12 @@
        writeBChan reportChan $ WorkerFinished myId s
        when (s == Pending) $ doWork reportChan myId
 
+-- KWQ: workers can report their total time taken and result, which can be displayed in a separate widget
+-- KWQ: with brick viewport scrolling, is itemMoreMessageAttr and associated even used?
+-- KWQ: vi/emacs style movement?  means top level entrypoints for those event processors (and move their utilities into hidding internal operations?)
 workDone :: Int -> ItemState -> t -> ItemFieldWidget n -> EventM n (ItemFieldWidget n)
 workDone workerNum toState _ fieldw =
-    return $ setItemState toState fieldw workerNum
+    setItemState toState fieldw workerNum
 
 
 workAttrs :: AttrMap
diff --git a/itemfield.cabal b/itemfield.cabal
--- a/itemfield.cabal
+++ b/itemfield.cabal
@@ -1,5 +1,5 @@
 name:                itemfield
-version:             1.2.4.2
+version:             1.2.5.0
 synopsis:            A brick Widget for selectable summary of many elements on a terminal
 description:         
 
diff --git a/src/TextUI/ItemField.hs b/src/TextUI/ItemField.hs
--- a/src/TextUI/ItemField.hs
+++ b/src/TextUI/ItemField.hs
@@ -85,9 +85,10 @@
 
 
 import           Brick.AttrMap
-import           Brick.Main (lookupViewport)
+import           Brick.Main (lookupViewport, invalidateCache, invalidateCacheEntry)
 import           Brick.Types
 import           Brick.Widgets.Core
+import           Control.Monad (foldM)
 import           Data.List
 import           Data.Maybe (fromMaybe)
 import qualified Data.Text as T
@@ -118,8 +119,10 @@
 -- using the Fixed horizontal and vertical growth policies.
 itemFieldWidget :: (Show n, Ord n) => ItemFieldWidget n -> Widget n
 itemFieldWidget field =
+    -- n.b. Use "Vertical" and not "Both" and accept "invisible" items if output screen is too narrow.  This is better than enabling horizontal scrolling, at which point the group names are never scrolled back into view.  could change this by making each group/line scrollable independently...
     let i = reportExtent (getName field) $
             viewport (getName field) Vertical $
+            cached (getName field) $
             Widget Fixed Fixed $ fieldImageW field
         s = Widget Fixed Fixed . summaryW field
     in case elemIdent $ itemField field of
@@ -135,7 +138,7 @@
            (rdata, newImage) = itemFieldRender field attrmap width height
            cursor = CursorLocation cursorloc (Just $ getName field)
            cursorloc = itemFieldGetPos rdata field
-       return $ Result newImage [cursor] [VR cursorloc (1,1)] []
+       return $ Result newImage [cursor] [VR cursorloc (1,1)] []  -- KWQ: VR is internal.. can update with recent brick changes??
 
 summaryW :: ItemFieldWidget n -> (Int -> ItemState -> T.Text)
          -> RenderM n (Result n)
@@ -208,6 +211,9 @@
           KChar '~' -> setMark Marked fieldw $ allWithState Pending
           KChar 's' -> return $ onFldWidget clrItm markItem $ allWithState Good
           KChar 'f' -> return $ onFldWidget clrItm markItem $ allWithState Bad
+          KChar 'r' -> if MCtrl `elem` mods
+                       then invalidateCache >> return fieldw
+                       else return fieldw
           _ -> return fieldw
     in case event of
          EvKey key mods -> handleKey key mods
@@ -298,22 +304,23 @@
                   then foldl (changeItemState markState) field' selrange
                   else field'
         fld' = fld { itemField = field'' }
-    in return fld'
+    in invalidateCacheEntry (getName fld') >> return fld'
 
 
 -- ----------------------------------------------------------------------
 -- Marking Functions
 
 toggleMark :: ItemFieldWidget n -> [Int] -> EventM n (ItemFieldWidget n)
-toggleMark fieldw =
+toggleMark fieldw marks =
     let newSt8 = if selected `elem` marked then Free else Marked
         selected = curSel $ itemField fieldw
         marked = getMarked $ itemField fieldw
-    in setMark newSt8 fieldw
+    in invalidateCacheEntry (getName fieldw) >> setMark newSt8 fieldw marks
 
 setMark :: ItemState -> ItemFieldWidget n -> [Int] -> EventM n (ItemFieldWidget n)
-setMark newSt8 fieldw = return . foldl (setItemState newSt8) fieldw
+setMark newSt8 fieldw = foldM (setItemState newSt8) fieldw
 
+
 toggleAllMarks :: ItemFieldWidget n -> EventM n (ItemFieldWidget n)
 toggleAllMarks fieldw = toggleMark fieldw allItems
     where allItems = [0 .. length (itemst8 $ itemField fieldw) - 1]
@@ -367,12 +374,14 @@
 
 
 -- | Modifies the state of the specified item in the widget to the new value
-setItemState :: ItemState -> ItemFieldWidget n -> Int -> ItemFieldWidget n
-setItemState newState widget itemIdx =
-    widget { itemField = changeItemState newState (itemField widget) itemIdx }
+setItemState :: ItemState -> ItemFieldWidget n -> Int -> EventM n (ItemFieldWidget n)
+setItemState newState widget itemIdx = do
+  invalidateCacheEntry (getName widget)
+  return $ widget { itemField = changeItemState newState (itemField widget) itemIdx }
 
 
 -- | Modifies the state of all currently marked items in the widget.
-setMarkedItemsState :: ItemState -> ItemFieldWidget n -> ItemFieldWidget n
-setMarkedItemsState newState widget =
-    foldl (setItemState newState) widget $ getMarkedItems widget
+setMarkedItemsState :: ItemState -> ItemFieldWidget n -> EventM n (ItemFieldWidget n)
+setMarkedItemsState newState widget = do
+  invalidateCacheEntry (getName widget)
+  foldM (setItemState newState) widget $ getMarkedItems widget
diff --git a/src/TextUI/ItemField/Types.hs b/src/TextUI/ItemField/Types.hs
--- a/src/TextUI/ItemField/Types.hs
+++ b/src/TextUI/ItemField/Types.hs
@@ -9,6 +9,10 @@
 data ItemState = Free | Marked | Good | Bad | Pending deriving (Show,Eq)
 type ItemIdent = Maybe (Int -> ItemState -> T.Text)
 
+-- KWQ: if Items were Foldable, could auto-compute length?
+-- KWQ: if Items were Foldable, then ItemField would be Foldable?  If items and itemst8 were combined as :: [(Item, ItemState)] ?? (or otherwise ensuring that items and itemst8 were matching in length
+-- KWQ: ItemField is Functor over itemst8?
+
 numItems :: Items -> NumItems
 numItems (ItemGroup _ x) = numItems x
 numItems (Items n) = n
