diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for deriving-trans
 
+## 0.2.1.0 *27 Jan 2022*
+
+* Use StandaloneKindSignatures.
+* Add Haddock documentation.
+
 ## 0.2.0.0 *25 Jan 2022*
 
 * Completely change the idea of this project. Pretty much everything has been changed.
diff --git a/deriving-trans.cabal b/deriving-trans.cabal
--- a/deriving-trans.cabal
+++ b/deriving-trans.cabal
@@ -1,12 +1,17 @@
 cabal-version:       3.0
 name:                deriving-trans
-version:             0.2.0.0
-synopsis:            Derive monad type classes with DerivingVia
-description:         Deriving type class instances for monad transformer stacks can be tedious.
-                     By actually composing transformers with `ComposeT` we don't need to implement
-                     each type class for each transformer.
-                     Instead we need a single instance for `Elevator`, which will then help us pick
-                     the correct instance with DerivingVia.
+version:             0.2.1.0
+synopsis:            Derive instances for monad transformer stacks
+description:         Implementing instances for monad transformer stacks can be tedious.
+                     <https://hackage.haskell.org/package/mtl mtl> defines each instance for each transfomer.
+
+                     'Elevator' let's you access instances of the underlying monad of a transformer.
+                     Composing transformers with 'ComposeT' brings instances into scope during the
+                     initialization of a transformer stack.
+
+                     'Elevator' can be used with DerivingVia to select a specific transformer to
+                     derive instances for a transformer stack.
+                     'ComposeT' composes transformers and accumulates instances in a transformer stack.
 license:             BSD-3-Clause
 license-file:        LICENSE
 author:              Felix Springer
@@ -24,7 +29,6 @@
   --other-modules:
   build-depends:
     , base              >= 4.5     && < 5
-    , lifted-base       >= 0.2.3.2 && < 0.2.4
     , monad-control     >= 1.0.2.0 && < 1.1
     , mtl               >= 2.2.2   && < 2.3
     , transformers      >= 0.5.6.2 && < 0.5.7
@@ -51,6 +55,7 @@
     OverloadedStrings
     RankNTypes
     StandaloneDeriving
+    StandaloneKindSignatures
     TypeApplications
     TypeFamilies
   ghc-options: -Wall
diff --git a/src/Control/Monad/Trans/Compose.hs b/src/Control/Monad/Trans/Compose.hs
--- a/src/Control/Monad/Trans/Compose.hs
+++ b/src/Control/Monad/Trans/Compose.hs
@@ -13,12 +13,16 @@
 import Control.Monad.Writer.Class
 import Data.Kind
 
-newtype ComposeT
-  (t1 :: (Type -> Type) -> Type -> Type)
-  (t2 :: (Type -> Type) -> Type -> Type)
-  (m :: Type -> Type)
-  (a :: Type)
-    = ComposeT { deComposeT :: t1 (t2 m) a }
+-- | A newtype wrapper for two stacked monad transformers.
+--
+-- Access instances of the intermediate monad @('t2' 'm')@, whenever 't1' implements
+-- 'MonadTrans'/'MonadTransControl'.
+type ComposeT :: ((Type -> Type) -> Type -> Type) -- ^ 't1'
+              -> ((Type -> Type) -> Type -> Type) -- ^ 't2'
+              -> (Type -> Type) -- ^ 'm'
+              -> Type -- ^ 'a'
+              -> Type
+newtype ComposeT t1 t2 m a = ComposeT { deComposeT :: t1 (t2 m) a }
   deriving newtype (Applicative, Functor, Monad)
 
 instance (forall m. Monad m => Monad (t2 m), MonadTrans t1, MonadTrans t2) => MonadTrans (ComposeT t1 t2) where
@@ -29,7 +33,7 @@
   liftWith f = defaultLiftWith2 ComposeT deComposeT $ \ x -> f x
   restoreT = defaultRestoreT2 ComposeT
 
--- | Elevated to `m`.
+-- | Elevated to 'm'.
 deriving via Elevator (ComposeT t1 t2) m
   instance
     ( Monad (t1 (t2 m))
@@ -37,7 +41,7 @@
     , MonadIO m
     ) => MonadIO (ComposeT t1 t2 m)
 
--- | Elevated to `m`.
+-- | Elevated to 'm'.
 deriving via Elevator (ComposeT t1 t2) m
   instance
     ( Monad (t1 (t2 m))
@@ -45,7 +49,7 @@
     , MonadBase b m
     ) => MonadBase b (ComposeT t1 t2 m)
 
--- | Elevated to `m`.
+-- | Elevated to 'm'.
 deriving via Elevator (ComposeT t1 t2) m
   instance
     ( Monad (t1 (t2 m))
@@ -53,7 +57,7 @@
     , MonadBaseControl b m
     ) => MonadBaseControl b (ComposeT t1 t2 m)
 
--- | Elevated to `t2 m`.
+-- | Elevated to @('t2' 'm')@.
 deriving via Elevator t1 (t2 (m :: * -> *))
   instance
     ( Monad (t1 (t2 m))
@@ -61,7 +65,7 @@
     , MonadError e (t2 m)
     ) => MonadError e (ComposeT t1 t2 m)
 
--- | Elevated to `t2 m`.
+-- | Elevated to @('t2' 'm')@.
 deriving via Elevator t1 (t2 (m :: * -> *))
   instance
     ( Monad (t1 (t2 m))
@@ -69,7 +73,7 @@
     , MonadReader r (t2 m)
     ) => MonadReader r (ComposeT t1 t2 m)
 
--- | Elevated to `t2 m`.
+-- | Elevated to @('t2' 'm')@.
 deriving via Elevator t1 (t2 (m :: * -> *))
   instance
     ( Monad (t1 (t2 m))
@@ -77,7 +81,7 @@
     , MonadState s (t2 m)
     ) => MonadState s (ComposeT t1 t2 m)
 
--- | Elevated to `t2 m`.
+-- | Elevated to @('t2' 'm')@.
 deriving via Elevator t1 (t2 (m :: * -> *))
   instance
     ( Monad (t1 (t2 m))
@@ -85,12 +89,23 @@
     , MonadWriter w (t2 m)
     ) => MonadWriter w (ComposeT t1 t2 m)
 
-runComposeT :: (forall a. t1 (t2 m) a -> t2 m (StT t1 a))
-            -> (forall a. t2 m a -> m (StT t2 a))
+-- | Run a transformer stack.
+--
+-- This function takes the two individual monad transformer runners as arguments.
+runComposeT :: (forall a. t1 (t2 m) a -> t2 m (StT t1 a)) -- ^ run 't1'
+            -> (forall a. t2 m a -> m (StT t2 a)) -- ^ run 't2'
             -> (forall a. ComposeT t1 t2 m a -> m (StT t2 (StT t1 a)))
 runComposeT runT1 runT2 = runT2 . runT1 . deComposeT
 
-runComposeT' :: (t1 (t2 m) a -> t2 m a)
-             -> (t2 m a -> m a)
+-- | Equivalent to 'runComposeT', but discards the monadic state 'StT'.
+-- This is a simple approach when your monad transformer stack doesn't carry monadic state.
+--
+-- @
+-- 'StT' ('ComposeT' 't1' 't2') a ~ a
+-- @
+--
+-- This can be used to improve error messages when modifying a monad transformer stack.
+runComposeT' :: (t1 (t2 m) a -> t2 m a) -- ^ run 't1'
+             -> (t2 m a -> m a) -- ^ run 't2'
              -> (ComposeT t1 t2 m a -> m a)
 runComposeT' runT1 runT2 = runT2 . runT1 . deComposeT
diff --git a/src/Control/Monad/Trans/Elevator.hs b/src/Control/Monad/Trans/Elevator.hs
--- a/src/Control/Monad/Trans/Elevator.hs
+++ b/src/Control/Monad/Trans/Elevator.hs
@@ -11,40 +11,96 @@
 import Control.Monad.Writer.Class
 import Data.Kind
 
-newtype Elevator
-  (t :: (Type -> Type) -> Type -> Type)
-  (m :: Type -> Type)
-  (a :: Type)
-    = Ascend { descend :: t m a }
+-- | A newtype wrapper for monad transformers.
+--
+-- Access instances of the inner monad 'm'.
+type Elevator :: ((Type -> Type) -> Type -> Type) -- ^ 't'
+              -> (Type -> Type) -- ^ 'm'
+              -> Type -- ^ 'a'
+              -> Type
+newtype Elevator t m a = Ascend { descend :: t m a }
   deriving newtype (Applicative, Functor, Monad)
+  deriving newtype (MonadTrans, MonadTransControl)
 
 instance (Monad (t m), MonadTrans t, MonadBase b m) => MonadBase b (Elevator t m) where
-  liftBase = Ascend . lift . liftBase
+  liftBase = lift . liftBase
 
 instance (Monad (t m), MonadTransControl t, MonadBaseControl b m) => MonadBaseControl b (Elevator t m) where
   type StM (Elevator t m) a = StM m (StT t a)
-  liftBaseWith f = Ascend $ liftWith $ \ runT -> liftBaseWith $ \ runInBase -> f $ runInBase . runT . descend
-  restoreM = Ascend . restoreT . restoreM
+  liftBaseWith f = liftWith $ \ runT -> liftBaseWith $ \ runInBase -> f $ runInBase . runT
+  restoreM = restoreT . restoreM
 
 instance (Monad (t m), MonadTrans t, MonadIO m) => MonadIO (Elevator t m) where
-  liftIO = Ascend . lift . liftIO
+  liftIO = lift . liftIO
 
 instance (Monad (t m), MonadTransControl t, MonadError e m) => MonadError e (Elevator t m) where
-  throwError = Ascend . lift . throwError
-  catchError throwing catching = Ascend $ (restoreT . pure =<<) $ liftWith $ \ runT ->
-    catchError (runT $ descend throwing) (runT . descend . catching)
+  throwError = lift . throwError
+  catchError throwing catching = (restoreT . pure =<<) $ liftWith $ \ runT ->
+    catchError (runT throwing) (runT . catching)
 
 instance (Monad (t m), MonadTransControl t, MonadReader r m) => MonadReader r (Elevator t m) where
-  ask = Ascend $ lift ask
-  local f tma = Ascend $ (restoreT . pure =<<) $ liftWith $ \ runT ->
-    local f $ runT $ descend tma
+  ask = lift ask
+  local f tma = (restoreT . pure =<<) $ liftWith $ \ runT ->
+    local f $ runT tma
 
 instance (Monad (t m), MonadTrans t, MonadState s m) => MonadState s (Elevator t m) where
-  get = Ascend $ lift get
-  put = Ascend . lift . put
+  get = lift get
+  put = lift . put
 
 instance (Monad (t m), MonadTransControl t, MonadWriter w m) => MonadWriter w (Elevator t m) where
-  tell = Ascend . lift . tell
-  listen tma = Ascend $ liftWith (\ runT -> listen $ runT $ descend tma) >>= \ (sta, w) ->
+  tell = lift . tell
+  listen tma = liftWith (\ runT -> listen $ runT tma) >>= \ (sta, w) ->
     (, w) <$> restoreT (pure sta)
-  pass tma = Ascend $ lift . pass . pure =<< descend tma
+  pass tma = lift . pass . pure =<< tma
+
+-- * Examples
+--
+-- $examples
+--
+-- == Example 1: Recover submerged instances
+--
+-- Let's assume you want to define a monad transformer stack.
+--
+-- @
+-- newtype StackT m a = StackT { unStackT :: ReaderT Char (ReaderT Bool m) a }
+--   deriving newtype (Functor, Applicative Monad)
+-- @
+--
+-- Now you want to expose the inner @(MonadReader Bool)@ instance with @(StackT m)@.
+--
+-- Normally it's shadowed by the @(MonadReader Char)@ instance, but we can use @Elevator@ to access
+-- the inner transformer.
+--
+-- @
+--   deriving (MonadReader Bool) via (Elevator (ReaderT Char) (ReaderT Bool m))
+-- @
+--
+-- == Example 2: Custom transformer without boilerplate
+--
+-- Let's assume you have defined a monad transformer.
+--
+-- @
+-- newtype CustomT m a = CustomT { unComposeT :: IdentityT m a }
+--   deriving newtype (Functor, Applicative Monad)
+--   deriving newtype (MonadTrans, MonadTransControl)
+--
+-- runCustomT :: CustomT m a -> m a
+-- runCustomT = runIdentityT . unComposeT
+-- @
+--
+-- Now you want to use this monad transformer in a transformer stack.
+--
+-- @
+-- newtype StackT m a = { unStackT :: CustomT (ReaderT Bool m) a }
+--   deriving newtype (Functor, Applicative Monad)
+--   deriving newtype (MonadTrans, MonadTransControl)
+-- @
+--
+-- Unfortunately we can't derive a @Monad m => MonadReader Bool (StackT m)@ instance with
+-- GeneralizedNewtypeDeriving, without also adding the instance to @CustomT@.
+--
+-- To still derive this trivial instance we can use @Elevator@ with DerivingVia.
+--
+-- @
+--   deriving (MonadReader Bool) via (Elevator CustomT (ReaderT Bool m))
+-- @
