diff --git a/readme.md b/readme.md
new file mode 100644
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,72 @@
+
+# Table of Contents
+
+1.  [web-rep](#orgebbc06e)
+2.  [library reference](#org8d29302)
+3.  [Development](#orgddf3f50)
+
+
+<a id="orgebbc06e"></a>
+
+# web-rep
+
+[![img](https://img.shields.io/hackage/v/web-rep.svg)](https://hackage.haskell.org/package/web-rep) [![img](https://github.com/tonyday567/web-rep/workflows/haskell-ci/badge.svg)](https://github.com/tonyday567/web-rep/actions?query=workflow%3Ahaskell-ci)
+
+Various functions and representations for a web page.
+
+The best way to understand functionality is via running the example app:
+
+    cabal install
+    page-example --apptype SharedTest
+
+&#x2026; and then tune in to:
+
+<http://localhost:9160/>
+
+
+<a id="org8d29302"></a>
+
+# library reference
+
+-   [scotty](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference)
+-   [bootstrap](https://getbootstrap.com/)
+-   [bootstrap-slider](https://seiyria.com/bootstrap-slider)
+
+
+<a id="orgddf3f50"></a>
+
+# Development
+
+    (setq haskell-process-args-cabal-repl '("web-rep:exe:web-rep-example"))
+
+<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
+
+
+<colgroup>
+<col  class="org-left" />
+</colgroup>
+<tbody>
+<tr>
+<td class="org-left">web-rep:exe:web-rep-example</td>
+</tr>
+</tbody>
+</table>
+
+    :r
+    :set -Wno-type-defaults
+    :set -Wno-name-shadowing
+    :set -XOverloadedStrings
+    :set -XOverloadedLabels
+    :set -XDataKinds
+    import Prelude
+    import Box
+    import Web.Rep
+    import Optics.Core
+    import FlatParse.Basic
+    import MarkupParse
+    putStrLn "ok"
+
+    Ok, 11 modules loaded.
+    ghci
+    ok
+
diff --git a/readme.org b/readme.org
deleted file mode 100644
--- a/readme.org
+++ /dev/null
@@ -1,51 +0,0 @@
-* web-rep
-
-[[https://hackage.haskell.org/package/numhask-array][file:https://img.shields.io/hackage/v/web-rep.svg]] [[https://github.com/tonyday567/numhask-array/actions?query=workflow%3Ahaskell-ci][file:https://github.com/tonyday567/web-rep/workflows/haskell-ci/badge.svg]]
-
-Various functions and representations for a web page.
-
-The best way to understand functionality is via running the example app:
-
-#+begin_src sh :results output
-cabal install
-page-example --apptype SharedTest
-#+end_src
-
-... and then tune in to:
-
-http://localhost:9160/
-
-* library reference
-- [[https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference][scotty]]
-- [[https://getbootstrap.com/][bootstrap]]
-- [[https://seiyria.com/bootstrap-slider][bootstrap-slider]]
-
-* Development
-
-#+begin_src elisp
-(setq haskell-process-args-cabal-repl '("web-rep:exe:web-rep-example"))
-#+end_src
-
-#+RESULTS:
-| web-rep:exe:web-rep-example |
-
-#+begin_src haskell :results output :exports both
-:r
-:set -Wno-type-defaults
-:set -Wno-name-shadowing
-:set -XOverloadedStrings
-:set -XOverloadedLabels
-:set -XDataKinds
-import Prelude
-import Box
-import Web.Rep
-import Optics.Core
-import FlatParse.Basic
-import MarkupParse
-putStrLn "ok"
-#+end_src
-
-#+RESULTS:
-: Ok, 11 modules loaded.
-: ghci
-: ok
diff --git a/src/Web/Rep/Bootstrap.hs b/src/Web/Rep/Bootstrap.hs
--- a/src/Web/Rep/Bootstrap.hs
+++ b/src/Web/Rep/Bootstrap.hs
@@ -87,8 +87,7 @@
       <> element
         "div"
         ([Attr "class" "card-body"] <> batts)
-        ( maybe mempty (elementc "h5" [Attr "class" "card-title"]) t <> b
-        )
+        (maybe mempty (elementc "h5" [Attr "class" "card-title"]) t <> b)
 
 -- | A Html object based on the bootstrap accordion card concept.
 accordionCard :: Bool -> [Attr] -> ByteString -> ByteString -> ByteString -> ByteString -> Markup -> Markup
@@ -173,7 +172,7 @@
   m Markup
 accordion pre x hs = do
   idp' <- genNamePre pre
-  element "div" [Attr "class" "accordion m-1", Attr "id" idp'] <$> (mconcat <$> aCards idp')
+  element "div" [Attr "class" "accordion m-1", Attr "id" idp'] . mconcat <$> aCards idp'
   where
     aCards par = mapM (aCard par) hs
     aCard par (t, b) = do
@@ -185,7 +184,7 @@
 accordionChecked :: (MonadState Int m) => ByteString -> [(ByteString, Markup, Markup)] -> m Markup
 accordionChecked pre hs = do
   idp' <- genNamePre pre
-  element "div" [Attr "class" "accordion m-1", Attr "id" idp'] <$> (mconcat <$> aCards idp')
+  element "div" [Attr "class" "accordion m-1", Attr "id" idp'] . mconcat <$> aCards idp'
   where
     aCards par = mapM (aCard par) hs
     aCard par (l, bodyhtml, checkhtml) = do
diff --git a/src/Web/Rep/Html/Input.hs b/src/Web/Rep/Html/Input.hs
--- a/src/Web/Rep/Html/Input.hs
+++ b/src/Web/Rep/Html/Input.hs
@@ -287,8 +287,7 @@
           ]
             <> bool [] [Attr "checked" ""] checked
         )
-        ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "form-label-check mb-0"]) l
-        )
+        (maybe mempty (elementc "label" [Attr "for" i, Attr "class" "form-label-check mb-0"]) l)
     )
 markupInput _ (Input _ l i (Toggle pushed lab)) =
   element
diff --git a/src/Web/Rep/Render.hs b/src/Web/Rep/Render.hs
--- a/src/Web/Rep/Render.hs
+++ b/src/Web/Rep/Render.hs
@@ -12,7 +12,6 @@
   )
 where
 
-import Control.Applicative
 import Control.Monad
 import Data.ByteString (ByteString)
 import Data.ByteString qualified as B
diff --git a/src/Web/Rep/Shared.hs b/src/Web/Rep/Shared.hs
--- a/src/Web/Rep/Shared.hs
+++ b/src/Web/Rep/Shared.hs
@@ -16,7 +16,6 @@
   )
 where
 
-import Control.Applicative
 import Control.Monad
 import Control.Monad.State.Lazy
 import Data.Biapplicative
diff --git a/src/Web/Rep/SharedReps.hs b/src/Web/Rep/SharedReps.hs
--- a/src/Web/Rep/SharedReps.hs
+++ b/src/Web/Rep/SharedReps.hs
@@ -464,8 +464,7 @@
       element
         "div"
         []
-        ( dd' <> mconcat (zipWith (addSubtype t0) ts cs')
-        )
+        (dd' <> mconcat (zipWith (addSubtype t0) ts cs'))
     mmap dd' cs' = maybe (List.head cs') (cs' List.!!) (List.elemIndex dd' ts)
 
 -- | select test keys from a Map
diff --git a/test/doctests.hs b/test/doctests.hs
new file mode 100644
--- /dev/null
+++ b/test/doctests.hs
@@ -0,0 +1,8 @@
+module Main where
+
+import System.Environment (getArgs)
+import Test.DocTest (mainFromCabal)
+import Prelude (IO, (=<<))
+
+main :: IO ()
+main = mainFromCabal "web-rep" =<< getArgs
diff --git a/web-rep.cabal b/web-rep.cabal
--- a/web-rep.cabal
+++ b/web-rep.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: web-rep
-version: 0.12.1.0
+version: 0.12.2.0
 license: BSD-3-Clause
 license-file: LICENSE
 copyright: Tony Day (c) 2015
@@ -14,10 +14,13 @@
     An applicative-based, shared-data representation of a web page. 
 
 build-type: Simple
-tested-with: GHC == 8.10.7 || ==9.2.7 || ==9.4.7 || ==9.6.3 || ==9.8.1
+tested-with:
+    , GHC == 9.10.1
+    , GHC == 9.6.5
+    , GHC == 9.8.2
 extra-doc-files:
     ChangeLog.md
-    readme.org
+    readme.md
 
 source-repository head
     type: git
@@ -42,60 +45,7 @@
         -Wredundant-constraints
 
 common ghc2021-stanza
-    if impl ( ghc >= 9.2 )
-        default-language: GHC2021
-
-    if impl ( ghc < 9.2 )
-        default-language: Haskell2010
-        default-extensions:
-            BangPatterns
-            BinaryLiterals
-            ConstrainedClassMethods
-            ConstraintKinds
-            DeriveDataTypeable
-            DeriveFoldable
-            DeriveFunctor
-            DeriveGeneric
-            DeriveLift
-            DeriveTraversable
-            DoAndIfThenElse
-            EmptyCase
-            EmptyDataDecls
-            EmptyDataDeriving
-            ExistentialQuantification
-            ExplicitForAll
-            FlexibleContexts
-            FlexibleInstances
-            ForeignFunctionInterface
-            GADTSyntax
-            GeneralisedNewtypeDeriving
-            HexFloatLiterals
-            ImplicitPrelude
-            InstanceSigs
-            KindSignatures
-            MonomorphismRestriction
-            MultiParamTypeClasses
-            NamedFieldPuns
-            NamedWildCards
-            NumericUnderscores
-            PatternGuards
-            PolyKinds
-            PostfixOperators
-            RankNTypes
-            RelaxedPolyRec
-            ScopedTypeVariables
-            StandaloneDeriving
-            StarIsType
-            TraditionalRecordSyntax
-            TupleSections
-            TypeApplications
-            TypeOperators
-            TypeSynonymInstances
-
-    if impl ( ghc < 9.2 ) && impl ( ghc >= 8.10 )
-        default-extensions:
-            ImportQualifiedPost
-            StandaloneKindSignatures
+    default-language: GHC2021
 
 library
     import: ghc-options-stanza
@@ -121,7 +71,7 @@
         , unordered-containers  >=0.2 && <0.3
         , wai-middleware-static >=0.9 && <0.10
         , wai-websockets        >=3.0.1.2 && <3.1
-        , websockets            >=0.12 && <0.13
+        , websockets            >=0.12 && <0.14
     exposed-modules:
         Web.Rep
         Web.Rep.Bootstrap
@@ -148,3 +98,13 @@
         , optics-core          >=0.4 && <0.5
         , optparse-applicative >=0.17 && <0.19
         , web-rep
+
+test-suite doctests
+    import: ghc2021-stanza
+    main-is: doctests.hs
+    hs-source-dirs: test
+    build-depends:
+        , base             >=4.14 && <5
+        , doctest-parallel >=0.3 && <0.4
+    ghc-options: -threaded
+    type: exitcode-stdio-1.0
