diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.3.15.0
+
+-   Update demos
+-   Updates for pandoc 3.0 and bump version
+-   Reshuffle and deduplicate block handling code
+
 ## 0.3.14.0
 
 ### Main changes
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks.hs
--- a/lib-internal/Text/Pandoc/CrossRef/References/Blocks.hs
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks.hs
@@ -18,342 +18,100 @@
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 -}
 
-{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts, ScopedTypeVariables, LambdaCase #-}
 module Text.Pandoc.CrossRef.References.Blocks
   ( replaceAll
   ) where
 
-import Control.Monad.State hiding (get, modify)
+import Control.Monad.Reader
 import Data.List
-import qualified Data.Map as M
-import Data.Maybe
 import qualified Data.Text as T
-import qualified Data.Text.Read as T
-import qualified Text.Pandoc.Builder as B
+import Lens.Micro
 import Text.Pandoc.Definition
-import Text.Pandoc.Shared (blocksToInlines, stringify)
-import Text.Pandoc.Walk (walk)
+import Text.Pandoc.Shared (blocksToInlines)
 
-import Control.Applicative
-import Data.Default
-import Lens.Micro
-import Lens.Micro.Mtl
-import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Blocks.CodeBlock
+import Text.Pandoc.CrossRef.References.Blocks.Header
+import Text.Pandoc.CrossRef.References.Blocks.Math
+import Text.Pandoc.CrossRef.References.Blocks.Subfigures
+import Text.Pandoc.CrossRef.References.Blocks.Table
+import Text.Pandoc.CrossRef.References.Blocks.Util
+import Text.Pandoc.CrossRef.References.Monad
 import Text.Pandoc.CrossRef.Util.Options
-import Text.Pandoc.CrossRef.Util.Template
 import Text.Pandoc.CrossRef.Util.Util
 
-replaceAll :: (Data a) => Options -> a -> WS a
-replaceAll opts =
-    runReplace (mkRR (replaceBlock opts)
-      `extRR` replaceInline opts
-      `extRR` replaceInlineMany opts
-      )
-  . runSplitMath
-  . everywhere (mkT divBlocks `extT` spanInlines opts)
-  where
-    runSplitMath | tableEqns opts
-                 , not $ isLatexFormat (outFormat opts)
-                 = everywhere (mkT splitMath)
-                 | otherwise = id
-
-simpleTable :: [Alignment] -> [ColWidth] -> [[[Block]]] -> Block
-simpleTable align width bod = Table nullAttr noCaption (zip align width)
-  noTableHead [mkBody bod] noTableFoot
+replaceAll :: (Data a) => a -> WS a
+replaceAll x = do
+  opts <- ask
+  x & runReplace (mkRR replaceBlock
+    `extRR` replaceInlineMany
+    )
+    . runSplitMath opts
+    . everywhere (mkT divBlocks `extT` spanInlines opts)
   where
-  mkBody xs = TableBody nullAttr (RowHeadColumns 0) [] (map mkRow xs)
-  mkRow xs = Row nullAttr (map mkCell xs)
-  mkCell xs = Cell nullAttr AlignDefault (RowSpan 1) (ColSpan 1) xs
-  noCaption = Caption Nothing mempty
-  noTableHead = TableHead nullAttr []
-  noTableFoot = TableFoot nullAttr []
+    runSplitMath opts
+      | tableEqns opts
+      , not $ isLatexFormat (outFormat opts)
+      = everywhere (mkT splitMath)
+      | otherwise = id
 
-setLabel :: Options -> [Inline] -> [(T.Text, T.Text)] -> [(T.Text, T.Text)]
-setLabel opts idx
-  | setLabelAttribute opts
-  = (("label", stringify idx) :)
-  . filter ((/= "label") . fst)
-  | otherwise = id
+extractCaption :: Block -> Maybe [Inline]
+extractCaption = \case
+  Para caption -> Just caption
+  Div (_, dcls, _) [Para caption] | "caption" `elem` dcls -> Just caption
+  _ -> Nothing
 
-replaceBlock :: Options -> Block -> WS (ReplacedResult Block)
-replaceBlock opts (Header n (label, cls, attrs) text')
-  = do
-    let label' = if autoSectionLabels opts && not ("sec:" `T.isPrefixOf` label)
-                 then "sec:"<>label
-                 else label
-    unless ("unnumbered" `elem` cls) $ do
-      modifying curChap $ \cc ->
-        let ln = length cc
-            cl i = lookup "label" attrs <|> customHeadingLabel opts n i <|> customLabel opts "sec" i
-            inc l = let i = fst (last l) + 1 in init l <> [(i, cl i)]
-            cc' | ln > n = inc $ take n cc
-                | ln == n = inc cc
-                | otherwise = cc <> take (n-ln-1) implicitChapters <> [(1,cl 1)]
-            implicitChapters | numberSections opts = repeat (1, Nothing)
-                             | otherwise = repeat (0, Nothing)
-        in cc'
-      when ("sec:" `T.isPrefixOf` label') $ do
-        index  <- use curChap
-        modifying secRefs $ M.insert label' RefRec {
-          refIndex=index
-        , refTitle= text'
-        , refSubfigure = Nothing
-        }
-    cc <- use curChap
-    let textCC | numberSections opts
-               , sectionsDepth opts < 0
-               || n <= if sectionsDepth opts == 0 then chaptersDepth opts else sectionsDepth opts
-               , "unnumbered" `notElem` cls
-               = applyTemplate' (M.fromDistinctAscList [
-                    ("i", idxStr)
-                  , ("n", [Str $ T.pack $ show $ n - 1])
-                  , ("t", text')
-                  ]) $ secHeaderTemplate opts
-               | otherwise = text'
-        idxStr = chapPrefix (chapDelim opts) cc
-        attrs' | "unnumbered" `notElem` cls
-               = setLabel opts idxStr attrs
-               | otherwise = attrs
-    replaceNoRecurse $ Header n (label', cls, attrs') textCC
--- subfigures
-replaceBlock opts (Div (label,cls,attrs) images)
+replaceBlock :: Block -> WS (ReplacedResult Block)
+replaceBlock (Header n attr text') = runHeader n attr text'
+replaceBlock (Figure attr@(label, _, _) caption content)
   | "fig:" `T.isPrefixOf` label
-  , Para caption <- last images
-  = do
-    idxStr <- replaceAttr opts (Right label) (lookup "label" attrs) caption imgRefs
-    let (cont, st) = runState (runReplace (mkRR $ replaceSubfigs opts') $ init images) def
-        collectedCaptions = B.toList $
-            intercalate' (B.fromList $ ccsDelim opts)
-          $ map (B.fromList . collectCaps . snd)
-          $ sortOn (refIndex . snd)
-          $ filter (not . null . refTitle . snd)
-          $ M.toList
-          $ st^.imgRefs
-        collectCaps v =
-              applyTemplate
-                (chapPrefix (chapDelim opts) (refIndex v))
-                (refTitle v)
-                (ccsTemplate opts)
-        vars = M.fromDistinctAscList
-                  [ ("ccs", collectedCaptions)
-                  , ("i", idxStr)
-                  , ("t", caption)
-                  ]
-        capt = applyTemplate' vars $ subfigureTemplate opts
-    lastRef <- fromJust . M.lookup label <$> use imgRefs
-    modifying imgRefs $ \old ->
-        M.union
-          old
-          (M.map (\v -> v{refIndex = refIndex lastRef, refSubfigure = Just $ refIndex v})
-          $ st^.imgRefs)
-    case outFormat opts of
-          f | isLatexFormat f ->
-            replaceNoRecurse $ Div nullAttr $
-              [ RawBlock (Format "latex") "\\begin{pandoccrossrefsubfigures}" ]
-              <> cont <>
-              [ Para [RawInline (Format "latex") "\\caption["
-                       , Span nullAttr (removeFootnotes caption)
-                       , RawInline (Format "latex") "]"
-                       , Span nullAttr caption]
-              , RawBlock (Format "latex") $ mkLaTeXLabel label
-              , RawBlock (Format "latex") "\\end{pandoccrossrefsubfigures}"]
-          _  -> replaceNoRecurse $ Div (label, "subfigures":cls, setLabel opts idxStr attrs) $ toTable cont capt
-  where
-    opts' = opts
-              { figureTemplate = subfigureChildTemplate opts
-              , customLabel = \r i -> customLabel opts ("sub"<>r) i
-              }
-    removeFootnotes = walk removeFootnote
-    removeFootnote Note{} = Str ""
-    removeFootnote x = x
-    toTable :: [Block] -> [Inline] -> [Block]
-    toTable blks capt
-      | subfigGrid opts = [ simpleTable align (map ColWidth widths) (map blkToRow blks)
-                          , mkCaption opts "Image Caption" capt]
-      | otherwise = blks <> [mkCaption opts "Image Caption" capt]
-      where
-        align | Para ils:_ <- blks = replicate (length $ mapMaybe getWidth ils) AlignCenter
-              | otherwise = error "Misformatted subfigures block"
-        widths | Para ils:_ <- blks
-               = fixZeros $ mapMaybe getWidth ils
-               | otherwise = error "Misformatted subfigures block"
-        getWidth (Image (_id, _class, as) _ _)
-          = Just $ maybe 0 percToDouble $ lookup "width" as
-        getWidth _ = Nothing
-        fixZeros :: [Double] -> [Double]
-        fixZeros ws
-          = let nz = length $ filter (== 0) ws
-                rzw = (0.99 - sum ws) / fromIntegral nz
-            in if nz>0
-               then map (\x -> if x == 0 then rzw else x) ws
-               else ws
-        percToDouble :: T.Text -> Double
-        percToDouble percs
-          | Right (perc, "%") <- T.double percs
-          = perc/100.0
-          | otherwise = error "Only percent allowed in subfigure width!"
-        blkToRow :: Block -> [[Block]]
-        blkToRow (Para inls) = mapMaybe inlToCell inls
-        blkToRow x = [[x]]
-        inlToCell :: Inline -> Maybe [Block]
-        inlToCell (Image (id', cs, as) txt tgt)  = Just [Para [Image (id', cs, setW as) txt tgt]]
-        inlToCell _ = Nothing
-        setW as = ("width", "100%"):filter ((/="width") . fst) as
-replaceBlock opts (Div (label,clss,attrs) [Table tattr (Caption short (btitle:rest)) colspec header cells foot])
-  | not $ null title
+  = runFigure False attr caption content
+replaceBlock (Div attr@(label, _, _) content)
+  | "fig:" `T.isPrefixOf` label
+  , Just caption <- extractCaption $ last content
+  = case init content of
+      [Figure ("", [], []) _ content'] -- nested figure due to implicit_figures...
+        -> runFigure False attr (Caption Nothing [Para caption]) content'
+      [x] -> runFigure False attr (Caption Nothing [Para caption]) [x]
+      xs -> runSubfigures attr xs caption
+replaceBlock (Div attr@(label, _, _) [Table tattr (Caption short (btitle:rest)) colspec header cells foot])
+  | not $ null $ blocksToInlines [btitle]
   , "tbl:" `T.isPrefixOf` label
-  = do
-    idxStr <- replaceAttr opts (Right label) (lookup "label" attrs) title tblRefs
-    let title' =
-          case outFormat opts of
-              f | isLatexFormat f ->
-                RawInline (Format "latex") (mkLaTeXLabel label) : title
-              _  -> applyTemplate idxStr title $ tableTemplate opts
-        caption' = Caption short (walkReplaceInlines title' title btitle:rest)
-    replaceNoRecurse $ Div (label, clss, setLabel opts idxStr attrs) [Table tattr caption' colspec header cells foot]
-  where title = blocksToInlines [btitle]
-replaceBlock opts (Table (label,clss,attrs) (Caption short (btitle:rest)) colspec header cells foot)
-  | not $ null title
+  = runTable attr (Just tattr) short btitle rest colspec header cells foot
+replaceBlock (Table attr@(label, _, _) (Caption short (btitle:rest)) colspec header cells foot)
+  | not $ null $ blocksToInlines [btitle]
   , "tbl:" `T.isPrefixOf` label
-  = do
-    idxStr <- replaceAttr opts (Right label) (lookup "label" attrs) title tblRefs
-    let title' =
-          case outFormat opts of
-              f | isLatexFormat f ->
-                RawInline (Format "latex") (mkLaTeXLabel label) : title
-              _  -> applyTemplate idxStr title $ tableTemplate opts
-        caption' = Caption short (walkReplaceInlines title' title btitle:rest)
-    replaceNoRecurse $ Table (label, clss, setLabel opts idxStr attrs) caption' colspec header cells foot
-  where title = blocksToInlines [btitle]
-replaceBlock opts cb@(CodeBlock (label, classes, attrs) code)
+  = runTable attr Nothing short btitle rest colspec header cells foot
+replaceBlock (CodeBlock attr@(label, _, attrs) code)
   | not $ T.null label
   , "lst:" `T.isPrefixOf` label
   , Just caption <- lookup "caption" attrs
-  = case outFormat opts of
-      f
-        --if used with listings package,nothing shoud be done
-        | isLatexFormat f, listings opts -> noReplaceNoRecurse
-        --if not using listings, however, wrap it in a codelisting environment
-        | isLatexFormat f ->
-          replaceNoRecurse $ Div nullAttr [
-              RawBlock (Format "latex") "\\begin{codelisting}"
-            , Plain [
-                RawInline (Format "latex") "\\caption{"
-              , Str caption
-              , RawInline (Format "latex") "}"
-              ]
-            , cb
-            , RawBlock (Format "latex") "\\end{codelisting}"
-            ]
-      _ -> do
-        let cap = B.toList $ B.text caption
-        idxStr <- replaceAttr opts (Right label) (lookup "label" attrs) cap lstRefs
-        let caption' = applyTemplate idxStr cap $ listingTemplate opts
-        replaceNoRecurse $ Div (label, "listing":classes, []) [
-            mkCaption opts "Caption" caption'
-          , CodeBlock ("", classes, filter ((/="caption") . fst) $ setLabel opts idxStr attrs) code
-          ]
-replaceBlock opts
+  = runCodeBlock attr code $ Left caption
+replaceBlock
   (Div (label,"listing":divClasses, divAttrs)
     [Para caption, CodeBlock ("",cbClasses,cbAttrs) code])
   | not $ T.null label
   , "lst:" `T.isPrefixOf` label
-  = case outFormat opts of
-      f
-        --if used with listings package, return code block with caption
-        | isLatexFormat f, listings opts ->
-          replaceNoRecurse $ CodeBlock (label,classes,("caption",escapeLaTeX $ stringify caption):attrs) code
-        --if not using listings, however, wrap it in a codelisting environment
-        | isLatexFormat f ->
-          replaceNoRecurse $ Div nullAttr [
-              RawBlock (Format "latex") "\\begin{codelisting}"
-            , Para [
-                RawInline (Format "latex") "\\caption"
-              , Span nullAttr caption
-              ]
-            , CodeBlock (label,classes,attrs) code
-            , RawBlock (Format "latex") "\\end{codelisting}"
-            ]
-      _ -> do
-        idxStr <- replaceAttr opts (Right label) (lookup "label" attrs) caption lstRefs
-        let caption' = applyTemplate idxStr caption $ listingTemplate opts
-        replaceNoRecurse $ Div (label, "listing":classes, []) [
-            mkCaption opts "Caption" caption'
-          , CodeBlock ("", classes, setLabel opts idxStr attrs) code
-          ]
-  where attrs = divAttrs <> cbAttrs
-        classes = nub $ divClasses <> cbClasses
-replaceBlock opts (Para [Span sattrs@(label, cls, attrs) [Math DisplayMath eq]])
-  | not $ isLatexFormat (outFormat opts)
-  , tableEqns opts
-  = do
-    (eq', idxStr) <- replaceEqn opts sattrs eq
-    let mathfmt = if eqnBlockInlineMath opts then InlineMath else DisplayMath
-    replaceNoRecurse $ Div (label,cls,setLabel opts idxStr attrs) $
-      applyTemplate [Math mathfmt $ stringify idxStr] [Math mathfmt eq']
-        $ eqnBlockTemplate opts
-replaceBlock _ _ = noReplaceRecurse
-
-replaceEqn :: Options -> Attr -> T.Text -> WS (T.Text, [Inline])
-replaceEqn opts (label, _, attrs) eq = do
-  let label' | T.null label = Left "eq"
-             | otherwise = Right label
-  idxStrRaw <- replaceAttr opts label' (lookup "label" attrs) [] eqnRefs
-  let idxStr = applyTemplate' (M.fromDistinctAscList [("i", idxStrRaw)]) $ eqnIndexTemplate opts
-      eqTxt = applyTemplate' eqTxtVars $ eqnInlineTemplate opts :: [Inline]
-      eqTxtVars = M.fromDistinctAscList
-        [ ("e", [Str eq])
-        , ("i", idxStr)
-        , ("ri", idxStrRaw)
-        ]
-      eq' | tableEqns opts = eq
-          | otherwise = stringify eqTxt
-  return (eq', idxStr)
+  = runCodeBlock (label, nub $ divClasses <> cbClasses, divAttrs <> cbAttrs) code $ Right caption
+replaceBlock (Para [Span attr [Math DisplayMath eq]])
+  = runBlockMath attr eq
+replaceBlock _ = noReplaceRecurse
 
-replaceInlineMany :: Options -> [Inline] -> WS (ReplacedResult [Inline])
-replaceInlineMany opts (Span spanAttr@(label,clss,attrs) [Math DisplayMath eq]:xs)
-  | "eq:" `T.isPrefixOf` label || T.null label && autoEqnLabels opts
-  = replaceRecurse . (<>xs) =<< case outFormat opts of
-      f | isLatexFormat f ->
+replaceInlineMany :: [Inline] -> WS (ReplacedResult [Inline])
+replaceInlineMany (Span spanAttr@(label,clss,attrs) [Math DisplayMath eq]:xs) = do
+  opts <- ask
+  if "eq:" `T.isPrefixOf` label || T.null label && autoEqnLabels opts
+  then do
+    replaceRecurse . (<> xs) =<< if isLatexFormat $ outFormat opts
+      then
         pure [RawInline (Format "latex") "\\begin{equation}"
         , Span spanAttr [RawInline (Format "latex") eq]
         , RawInline (Format "latex") $ mkLaTeXLabel label <> "\\end{equation}"]
-      _ -> do
-        (eq', idxStr) <- replaceEqn opts spanAttr eq
+      else do
+        (eq', idxStr) <- replaceEqn spanAttr eq
         pure [Span (label,clss,setLabel opts idxStr attrs) [Math DisplayMath eq']]
-replaceInlineMany _ _ = noReplaceRecurse
-
-replaceInline :: Options -> Inline -> WS (ReplacedResult Inline)
-replaceInline opts (Image (label,cls,attrs) alt img@(_, tit))
-  | "fig:" `T.isPrefixOf` label && "fig:" `T.isPrefixOf` tit
-  = do
-    idxStr <- replaceAttr opts (Right label) (lookup "label" attrs) alt imgRefs
-    let alt' = case outFormat opts of
-          f | isLatexFormat f -> alt
-          _  -> applyTemplate idxStr alt $ figureTemplate opts
-    replaceNoRecurse $ Image (label,cls,setLabel opts idxStr attrs) alt' img
-replaceInline _ _ = noReplaceRecurse
-
-replaceSubfigs :: Options -> [Inline] -> WS (ReplacedResult [Inline])
-replaceSubfigs opts = (replaceNoRecurse . concat) <=< mapM (replaceSubfig opts)
-
-replaceSubfig :: Options -> Inline -> WS [Inline]
-replaceSubfig opts x@(Image (label,cls,attrs) alt (src, tit))
-  = do
-      let label' | "fig:" `T.isPrefixOf` label = Right label
-                 | T.null label = Left "fig"
-                 | otherwise  = Right $ "fig:" <> label
-      idxStr <- replaceAttr opts label' (lookup "label" attrs) alt imgRefs
-      case outFormat opts of
-        f | isLatexFormat f ->
-          return $ latexSubFigure x label
-        _  ->
-          let alt' = applyTemplate idxStr alt $ figureTemplate opts
-              tit' | "nocaption" `elem` cls = fromMaybe tit $ T.stripPrefix "fig:" tit
-                   | "fig:" `T.isPrefixOf` tit = tit
-                   | otherwise = "fig:" <> tit
-          in return [Image (label, cls, setLabel opts idxStr attrs) alt' (src, tit')]
-replaceSubfig _ x = return [x]
+  else noReplaceRecurse
+replaceInlineMany _ = noReplaceRecurse
 
 divBlocks :: Block -> Block
 divBlocks (Table tattr (Caption short (btitle:rest)) colspec header cells foot)
@@ -365,25 +123,6 @@
     title = blocksToInlines [btitle]
 divBlocks x = x
 
-walkReplaceInlines :: [Inline] -> [Inline] -> Block -> Block
-walkReplaceInlines newTitle title = walk replaceInlines
-  where
-  replaceInlines xs
-    | xs == title = newTitle
-    | otherwise = xs
-
-splitMath :: [Block] -> [Block]
-splitMath (Para ils:xs)
-  | length ils > 1 = map Para (split [] [] ils) <> xs
-  where
-    split res acc [] = reverse (reverse acc : res)
-    split res acc (x@(Span _ [Math DisplayMath _]):ys) =
-      split ([x] : reverse (dropSpaces acc) : res)
-            [] (dropSpaces ys)
-    split res acc (y:ys) = split res (y:acc) ys
-    dropSpaces = dropWhile isSpace
-splitMath xs = xs
-
 spanInlines :: Options -> [Inline] -> [Inline]
 spanInlines opts (math@(Math DisplayMath _eq):ils)
   | c:ils' <- dropWhile isSpace ils
@@ -392,46 +131,3 @@
   | autoEqnLabels opts
   = Span nullAttr [math]:ils
 spanInlines _ x = x
-
-replaceAttr :: Options -> Either T.Text T.Text -> Maybe T.Text -> [Inline] -> Lens References References RefMap RefMap -> WS [Inline]
-replaceAttr o label refLabel title prop
-  = do
-    chap  <- take (chaptersDepth o) `fmap` use curChap
-    prop' <- use prop
-    let i = 1+ (M.size . M.filter (\x -> (chap == init (refIndex x)) && isNothing (refSubfigure x)) $ prop')
-        index = chap <> [(i, refLabel <|> customLabel o ref i)]
-        ref = either id (T.takeWhile (/=':')) label
-        label' = either (<> T.pack (':' : show index)) id label
-    when (M.member label' prop') $
-      error . T.unpack $ "Duplicate label: " <> label'
-    modifying prop $ M.insert label' RefRec {
-      refIndex= index
-    , refTitle= title
-    , refSubfigure = Nothing
-    }
-    return $ chapPrefix (chapDelim o) index
-
-latexSubFigure :: Inline -> T.Text -> [Inline]
-latexSubFigure (Image (_, cls, attrs) alt (src, title)) label =
-  let
-    title' = fromMaybe title $ T.stripPrefix "fig:" title
-    texlabel | T.null label = []
-             | otherwise = [RawInline (Format "latex") $ mkLaTeXLabel label]
-    texalt | "nocaption" `elem` cls  = []
-           | otherwise = concat
-              [ [ RawInline (Format "latex") "["]
-              , alt
-              , [ RawInline (Format "latex") "]"]
-              ]
-    img = Image (label, cls, attrs) alt (src, title')
-  in concat [
-      [ RawInline (Format "latex") "\\subfloat" ]
-      , texalt
-      , [Span nullAttr $ img:texlabel]
-      ]
-latexSubFigure x _ = [x]
-
-mkCaption :: Options -> T.Text -> [Inline] -> Block
-mkCaption opts style
-  | outFormat opts == Just (Format "docx") = Div ("", [], [("custom-style", style)]) . return . Para
-  | otherwise = Para
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks/CodeBlock.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/CodeBlock.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/CodeBlock.hs
@@ -0,0 +1,67 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
+
+module Text.Pandoc.CrossRef.References.Blocks.CodeBlock where
+
+import Control.Monad.Reader.Class
+import qualified Data.Text as T
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (stringify)
+import qualified Text.Pandoc.Builder as B
+import Data.Function ((&))
+
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
+import Text.Pandoc.CrossRef.References.Blocks.Util (mkCaption, replaceAttr, setLabel)
+import Text.Pandoc.CrossRef.Util.Options
+import Text.Pandoc.CrossRef.Util.Template
+import Text.Pandoc.CrossRef.Util.Util
+
+runCodeBlock :: Attr -> T.Text -> Either T.Text [Inline] -> WS (ReplacedResult Block)
+runCodeBlock (label, classes, attrs) code eCaption = do
+  opts <- ask
+  case outFormat opts of
+    f --if used with listings package,nothing should be done
+      | isLatexFormat f, listings opts -> eCaption &
+        either
+          (const noReplaceNoRecurse)
+          (\caption -> replaceNoRecurse $
+            CodeBlock (label,classes,("caption",escapeLaTeX $ stringify caption):attrs) code)
+      --if not using listings, however, wrap it in a codelisting environment
+      | isLatexFormat f ->
+        replaceNoRecurse $ Div nullAttr [
+            RawBlock (Format "latex") "\\begin{codelisting}"
+          , Plain [
+              RawInline (Format "latex") "\\caption"
+            , Span nullAttr $ either (pure . Str) id eCaption
+            ]
+          , CodeBlock (label, classes, attrs) code
+          , RawBlock (Format "latex") "\\end{codelisting}"
+          ]
+    _ -> do
+      let cap = either (B.toList . B.text) id eCaption
+      idxStr <- replaceAttr (Right label) (lookup "label" attrs) cap lstRefs
+      let caption' = applyTemplate idxStr cap $ listingTemplate opts
+      replaceNoRecurse $ Div (label, "listing":classes, []) [
+          mkCaption opts "Caption" caption'
+        , CodeBlock ("", classes, filter ((/="caption") . fst) $ setLabel opts idxStr attrs) code
+        ]
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Header.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Header.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Header.hs
@@ -0,0 +1,79 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
+
+module Text.Pandoc.CrossRef.References.Blocks.Header where
+
+import Control.Monad.Reader.Class
+import Control.Monad.State hiding (get, modify)
+import qualified Data.Map as M
+import qualified Data.Text as T
+import Text.Pandoc.Definition
+
+import Control.Applicative
+import Lens.Micro.Mtl
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
+import Text.Pandoc.CrossRef.References.Blocks.Util (setLabel)
+import Text.Pandoc.CrossRef.Util.Options
+import Text.Pandoc.CrossRef.Util.Template
+import Text.Pandoc.CrossRef.Util.Util
+
+runHeader :: Int -> Attr -> [Inline] -> WS (ReplacedResult Block)
+runHeader n (label, cls, attrs) text' = do
+  opts <- ask
+  let label' = if autoSectionLabels opts && not ("sec:" `T.isPrefixOf` label)
+                then "sec:"<>label
+                else label
+  unless ("unnumbered" `elem` cls) $ do
+    modifying curChap $ \cc ->
+      let ln = length cc
+          cl i = lookup "label" attrs <|> customHeadingLabel opts n i <|> customLabel opts "sec" i
+          inc l = let i = fst (last l) + 1 in init l <> [(i, cl i)]
+          cc' | ln > n = inc $ take n cc
+              | ln == n = inc cc
+              | otherwise = cc <> take (n-ln-1) implicitChapters <> [(1,cl 1)]
+          implicitChapters | numberSections opts = repeat (1, Nothing)
+                            | otherwise = repeat (0, Nothing)
+      in cc'
+    when ("sec:" `T.isPrefixOf` label') $ do
+      index  <- use curChap
+      modifying secRefs $ M.insert label' RefRec {
+        refIndex=index
+      , refTitle= text'
+      , refSubfigure = Nothing
+      }
+  cc <- use curChap
+  let textCC | numberSections opts
+              , sectionsDepth opts < 0
+              || n <= if sectionsDepth opts == 0 then chaptersDepth opts else sectionsDepth opts
+              , "unnumbered" `notElem` cls
+              = applyTemplate' (M.fromDistinctAscList [
+                  ("i", idxStr)
+                , ("n", [Str $ T.pack $ show $ n - 1])
+                , ("t", text')
+                ]) $ secHeaderTemplate opts
+              | otherwise = text'
+      idxStr = chapPrefix (chapDelim opts) cc
+      attrs' | "unnumbered" `notElem` cls
+              = setLabel opts idxStr attrs
+              | otherwise = attrs
+  replaceNoRecurse $ Header n (label', cls, attrs') textCC
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Math.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Math.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Math.hs
@@ -0,0 +1,77 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
+
+module Text.Pandoc.CrossRef.References.Blocks.Math where
+
+import Control.Monad.Reader.Class
+import qualified Data.Map as M
+import qualified Data.Text as T
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (stringify)
+
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
+import Text.Pandoc.CrossRef.References.Blocks.Util (setLabel, replaceAttr)
+import Text.Pandoc.CrossRef.Util.Options
+import Text.Pandoc.CrossRef.Util.Template
+import Text.Pandoc.CrossRef.Util.Util
+
+runBlockMath :: Attr -> T.Text -> WS (ReplacedResult Block)
+runBlockMath (label, cls, attrs) eq = do
+  opts <- ask
+  if tableEqns opts && not (isLatexFormat (outFormat opts))
+  then do
+    (eq', idxStr) <- replaceEqn (label, cls, attrs) eq
+    let mathfmt = if eqnBlockInlineMath opts then InlineMath else DisplayMath
+    replaceNoRecurse $ Div (label,cls,setLabel opts idxStr attrs) $
+      applyTemplate [Math mathfmt $ stringify idxStr] [Math mathfmt eq']
+        $ eqnBlockTemplate opts
+  else noReplaceRecurse
+
+replaceEqn :: Attr -> T.Text -> WS (T.Text, [Inline])
+replaceEqn (label, _, attrs) eq = do
+  opts <- ask
+  let label' | T.null label = Left "eq"
+             | otherwise = Right label
+  idxStrRaw <- replaceAttr label' (lookup "label" attrs) [] eqnRefs
+  let idxStr = applyTemplate' (M.fromDistinctAscList [("i", idxStrRaw)]) $ eqnIndexTemplate opts
+      eqTxt = applyTemplate' eqTxtVars $ eqnInlineTemplate opts :: [Inline]
+      eqTxtVars = M.fromDistinctAscList
+        [ ("e", [Str eq])
+        , ("i", idxStr)
+        , ("ri", idxStrRaw)
+        ]
+      eq' | tableEqns opts = eq
+          | otherwise = stringify eqTxt
+  return (eq', idxStr)
+
+splitMath :: [Block] -> [Block]
+splitMath (Para ils:xs)
+  | length ils > 1 = map Para (split [] [] ils) <> xs
+  where
+    split res acc [] = reverse (reverse acc : res)
+    split res acc (x@(Span _ [Math DisplayMath _]):ys) =
+      split ([x] : reverse (dropSpaces acc) : res)
+            [] (dropSpaces ys)
+    split res acc (y:ys) = split res (y:acc) ys
+    dropSpaces = dropWhile isSpace
+splitMath xs = xs
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Subfigures.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Subfigures.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Subfigures.hs
@@ -0,0 +1,218 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts, LambdaCase #-}
+
+module Text.Pandoc.CrossRef.References.Blocks.Subfigures where
+
+import Control.Monad.Reader
+import Control.Monad.State hiding (get, modify)
+import qualified Data.Map as M
+import qualified Data.Text as T
+import qualified Data.Text.Read as T
+import Text.Pandoc.Definition
+import qualified Text.Pandoc.Builder as B
+import Data.Default (def)
+import Data.List
+import Data.Maybe
+import Text.Pandoc.Walk (walk)
+import Lens.Micro
+import Lens.Micro.Mtl
+import Text.Pandoc.Shared (blocksToInlines)
+
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
+import Text.Pandoc.CrossRef.References.Blocks.Util (setLabel, replaceAttr, walkReplaceInlines)
+import Text.Pandoc.CrossRef.Util.Options
+import Text.Pandoc.CrossRef.Util.Template
+import Text.Pandoc.CrossRef.Util.Util
+
+runSubfigures :: Attr -> [Block] -> [Inline] -> WS (ReplacedResult Block)
+runSubfigures (label, cls, attrs) images caption = do
+  opts <- ask
+  idxStr <- replaceAttr (Right label) (lookup "label" attrs) caption imgRefs
+  let (cont, st) = flip runState def $ flip runReaderT opts' $ runWS $ runReplace (mkRR replaceSubfigs `extRR` doFigure) $ images
+      doFigure :: Block -> WS (ReplacedResult Block)
+      doFigure (Figure attr caption' content) = runFigure True attr caption' content
+      doFigure _ = noReplaceRecurse
+      opts' = opts
+          { figureTemplate = subfigureChildTemplate opts
+          , customLabel = \r i -> customLabel opts ("sub"<>r) i
+          }
+      collectedCaptions = B.toList $
+          intercalate' (B.fromList $ ccsDelim opts)
+        $ map (B.fromList . collectCaps . snd)
+        $ sortOn (refIndex . snd)
+        $ filter (not . null . refTitle . snd)
+        $ M.toList
+        $ st^.imgRefs
+      collectCaps v =
+            applyTemplate
+              (chapPrefix (chapDelim opts) (refIndex v))
+              (refTitle v)
+              (ccsTemplate opts)
+      vars = M.fromDistinctAscList
+                [ ("ccs", collectedCaptions)
+                , ("i", idxStr)
+                , ("t", caption)
+                ]
+      capt = applyTemplate' vars $ subfigureTemplate opts
+  lastRef <- fromJust . M.lookup label <$> use imgRefs
+  modifying imgRefs $ \old ->
+      M.union
+        old
+        (M.map (\v -> v{refIndex = refIndex lastRef, refSubfigure = Just $ refIndex v})
+        $ st^.imgRefs)
+  case outFormat opts of
+    f | isLatexFormat f ->
+      replaceNoRecurse $ Div nullAttr $
+        [ RawBlock (Format "latex") "\\begin{pandoccrossrefsubfigures}" ]
+        <> cont <>
+        [ Para [RawInline (Format "latex") "\\caption["
+                  , Span nullAttr (removeFootnotes caption)
+                  , RawInline (Format "latex") "]"
+                  , Span nullAttr caption]
+        , RawBlock (Format "latex") $ mkLaTeXLabel label
+        , RawBlock (Format "latex") "\\end{pandoccrossrefsubfigures}"]
+    _ -> replaceNoRecurse
+      $ Figure (label, "subfigures":cls, setLabel opts idxStr attrs) (Caption Nothing [Para capt])
+      $ toTable opts cont
+  where
+    removeFootnotes = walk removeFootnote
+    removeFootnote Note{} = Str ""
+    removeFootnote x = x
+    toTable :: Options -> [Block] -> [Block]
+    toTable opts blks
+      | isLatexFormat $ outFormat opts = concatMap imagesToFigures blks
+      | subfigGrid opts = [simpleTable align (map ColWidth widths) (map (fmap pure . blkToRow) blks)]
+      | otherwise = blks
+      where
+        align | b:_ <- blks = let ils = blocksToInlines [b] in replicate (length $ mapMaybe getWidth ils) AlignCenter
+              | otherwise = error "Misformatted subfigures block"
+        widths | b:_ <- blks = let ils = blocksToInlines [b] in fixZeros $ mapMaybe getWidth ils
+               | otherwise = error "Misformatted subfigures block"
+        getWidth (Image (_id, _class, as) _ _)
+          = Just $ maybe 0 percToDouble $ lookup "width" as
+        getWidth _ = Nothing
+        fixZeros :: [Double] -> [Double]
+        fixZeros ws
+          = let nz = length $ filter (== 0) ws
+                rzw = (0.99 - sum ws) / fromIntegral nz
+            in if nz>0
+                then map (\x -> if x == 0 then rzw else x) ws
+                else ws
+        percToDouble :: T.Text -> Double
+        percToDouble percs
+          | Right (perc, "%") <- T.double percs
+          = perc/100.0
+          | otherwise = error "Only percent allowed in subfigure width!"
+        blkToRow :: Block -> [Block]
+        blkToRow (Para inls) = mapMaybe inlToCell inls
+        blkToRow x = [x]
+        inlToCell :: Inline -> Maybe Block
+        inlToCell (Image (id', cs, as) txt tgt) = Just $
+          Figure (id', cs, as) (Caption Nothing [Para txt]) [Plain [Image ("", cs, setW as) txt tgt]]
+        inlToCell _ = Nothing
+        setW as = ("width", "100%"):filter ((/="width") . fst) as
+
+replaceSubfigs :: [Inline] -> WS (ReplacedResult [Inline])
+replaceSubfigs = (replaceNoRecurse . concat) <=< mapM replaceSubfig
+
+imagesToFigures :: Block -> [Block]
+imagesToFigures = \case
+  x@Figure{} -> [x]
+  Para xs -> mapMaybe imageToFigure xs
+  Plain xs -> mapMaybe imageToFigure xs
+  _ -> []
+
+imageToFigure :: Inline -> Maybe Block
+imageToFigure = \case
+  Image (label,cls,attrs) alt tgt -> Just $ Figure (label, cls, attrs) (Caption Nothing [Para alt])
+    [Plain [Image ("",cls,attrs) alt tgt]]
+  _ -> Nothing
+
+replaceSubfig :: Inline -> WS [Inline]
+replaceSubfig x@(Image (label,cls,attrs) alt tgt)
+  = do
+      opts <- ask
+      let label' = normalizeLabel label
+      idxStr <- replaceAttr label' (lookup "label" attrs) alt imgRefs
+      let alt' = applyTemplate idxStr alt $ figureTemplate opts
+      case outFormat opts of
+        f | isLatexFormat f ->
+          pure $ latexSubFigure x label
+        _ -> return [Image (label, cls, setLabel opts idxStr attrs) alt' tgt]
+replaceSubfig x = return [x]
+
+latexSubFigure :: Inline -> T.Text -> [Inline]
+latexSubFigure (Image (_, cls, attrs) alt (src, title)) label =
+  let
+    title' = fromMaybe title $ T.stripPrefix "fig:" title
+    texlabel | T.null label = []
+             | otherwise = [RawInline (Format "latex") $ mkLaTeXLabel label]
+    texalt | "nocaption" `elem` cls  = []
+           | otherwise = concat
+              [ [ RawInline (Format "latex") "["]
+              , alt
+              , [ RawInline (Format "latex") "]"]
+              ]
+    img = Image (label, cls, attrs) alt (src, title')
+  in concat [
+      [ RawInline (Format "latex") "\\subfloat" ]
+      , texalt
+      , [Span nullAttr $ img:texlabel]
+      ]
+latexSubFigure x _ = [x]
+
+normalizeLabel :: T.Text -> Either T.Text T.Text
+normalizeLabel label
+  | "fig:" `T.isPrefixOf` label = Right label
+  | T.null label = Left "fig"
+  | otherwise  = Right $ "fig:" <> label
+
+simpleTable :: [Alignment] -> [ColWidth] -> [[[Block]]] -> Block
+simpleTable align width bod = Table nullAttr noCaption (zip align width)
+  noTableHead [mkBody bod] noTableFoot
+  where
+  mkBody xs = TableBody nullAttr (RowHeadColumns 0) [] (map mkRow xs)
+  mkRow xs = Row nullAttr (map mkCell xs)
+  mkCell xs = Cell nullAttr AlignDefault (RowSpan 1) (ColSpan 1) xs
+  noCaption = Caption Nothing mempty
+  noTableHead = TableHead nullAttr []
+  noTableFoot = TableFoot nullAttr []
+
+runFigure :: Bool -> Attr -> Caption -> [Block] -> WS (ReplacedResult Block)
+runFigure subFigure (label, cls, fattrs) (Caption short (btitle : rest)) content = do
+  opts <- ask
+  let label' = normalizeLabel label
+  let title = blocksToInlines [btitle]
+      attrs = fromMaybe fattrs $ case blocksToInlines content of
+        [Image (_, _, as) _ _] -> Just as
+        _ -> Nothing
+  idxStr <- replaceAttr label' (lookup "label" attrs) title imgRefs
+  let title' = case outFormat opts of
+        f | isLatexFormat f -> title
+        _  -> applyTemplate idxStr title $ figureTemplate opts
+      caption' = Caption short (walkReplaceInlines title' title btitle:rest)
+  replaceNoRecurse $
+    if subFigure && isLatexFormat (outFormat opts)
+    then Plain $ latexSubFigure (head $ blocksToInlines content) label
+    else Figure (label,cls,setLabel opts idxStr attrs) caption' content
+runFigure _ _ _ _ = noReplaceNoRecurse
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Table.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Table.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Table.hs
@@ -0,0 +1,53 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
+
+module Text.Pandoc.CrossRef.References.Blocks.Table where
+
+import Control.Monad.Reader.Class
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (blocksToInlines)
+import Data.Function ((&))
+
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
+import Text.Pandoc.CrossRef.References.Blocks.Util (setLabel, replaceAttr, walkReplaceInlines)
+import Text.Pandoc.CrossRef.Util.Options
+import Text.Pandoc.CrossRef.Util.Template
+import Text.Pandoc.CrossRef.Util.Util
+
+runTable :: Attr -> Maybe Attr -> Maybe ShortCaption -> Block -> [Block] -> [ColSpec] -> TableHead -> [TableBody] -> TableFoot -> WS (ReplacedResult Block)
+runTable (label, clss, attrs) mtattr short btitle rest colspec header cells foot = do
+  opts <- ask
+  idxStr <- replaceAttr (Right label) (lookup "label" attrs) title tblRefs
+  let title' =
+        case outFormat opts of
+            f | isLatexFormat f ->
+              RawInline (Format "latex") (mkLaTeXLabel label) : title
+            _  -> applyTemplate idxStr title $ tableTemplate opts
+      caption' = Caption short (walkReplaceInlines title' title btitle:rest)
+  replaceNoRecurse $ (mtattr &
+    maybe
+      (Table (label, clss, setLabel opts idxStr attrs))
+      (\tattr a b c d -> Div (label, clss, setLabel opts idxStr attrs) . pure . Table tattr a b c d)
+    )
+    caption' colspec header cells foot
+  where title = blocksToInlines [btitle]
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Util.hs b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Util.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Blocks/Util.hs
@@ -0,0 +1,78 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
+
+module Text.Pandoc.CrossRef.References.Blocks.Util where
+
+import Control.Monad.Reader.Class
+import Control.Monad.State hiding (get, modify)
+import qualified Data.Map as M
+import Data.Maybe
+import qualified Data.Text as T
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (stringify)
+import Text.Pandoc.Walk (walk)
+
+import Control.Applicative
+import Lens.Micro
+import Lens.Micro.Mtl
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
+import Text.Pandoc.CrossRef.Util.Options
+import Text.Pandoc.CrossRef.Util.Util
+
+setLabel :: Options -> [Inline] -> [(T.Text, T.Text)] -> [(T.Text, T.Text)]
+setLabel opts idx
+  | setLabelAttribute opts
+  = (("label", stringify idx) :)
+  . filter ((/= "label") . fst)
+  | otherwise = id
+
+walkReplaceInlines :: [Inline] -> [Inline] -> Block -> Block
+walkReplaceInlines newTitle title = walk replaceInlines
+  where
+  replaceInlines xs
+    | xs == title = newTitle
+    | otherwise = xs
+
+replaceAttr :: Either T.Text T.Text -> Maybe T.Text -> [Inline] -> Lens References References RefMap RefMap -> WS [Inline]
+replaceAttr label refLabel title prop
+  = do
+    o <- ask
+    chap  <- take (chaptersDepth o) `fmap` use curChap
+    prop' <- use prop
+    let i = 1+ (M.size . M.filter (\x -> (chap == init (refIndex x)) && isNothing (refSubfigure x)) $ prop')
+        index = chap <> [(i, refLabel <|> customLabel o ref i)]
+        ref = either id (T.takeWhile (/=':')) label
+        label' = either (<> T.pack (':' : show index)) id label
+    when (M.member label' prop') $
+      error . T.unpack $ "Duplicate label: " <> label'
+    modifying prop $ M.insert label' RefRec {
+      refIndex= index
+    , refTitle= title
+    , refSubfigure = Nothing
+    }
+    return $ chapPrefix (chapDelim o) index
+
+mkCaption :: Options -> T.Text -> [Inline] -> Block
+mkCaption opts style
+  | outFormat opts == Just (Format "docx") = Div ("", [], [("custom-style", style)]) . return . Para
+  | otherwise = Para
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/List.hs b/lib-internal/Text/Pandoc/CrossRef/References/List.hs
--- a/lib-internal/Text/Pandoc/CrossRef/References/List.hs
+++ b/lib-internal/Text/Pandoc/CrossRef/References/List.hs
@@ -18,10 +18,11 @@
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 -}
 
-{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings, RecordWildCards, LambdaCase #-}
 module Text.Pandoc.CrossRef.References.List (listOf) where
 
 import Data.List
+import Control.Monad.Reader
 import qualified Data.Map as M
 import qualified Data.Text as T
 import Text.Pandoc.Definition
@@ -29,38 +30,39 @@
 
 import Lens.Micro.Mtl
 import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
 import Text.Pandoc.CrossRef.Util.Options
 import Text.Pandoc.CrossRef.Util.Util
 import Text.Pandoc.CrossRef.Util.Template
 
-listOf :: Options -> [Block] -> WS [Block]
-listOf Options{outFormat=f} x | isLatexFormat f = return x
-listOf opts (RawBlock fmt "\\listoffigures":xs)
-  | isLaTeXRawBlockFmt fmt
-  = use imgRefs >>= makeList "fig" opts lofItemTemplate lofTitle xs
-listOf opts (RawBlock fmt "\\listoftables":xs)
-  | isLaTeXRawBlockFmt fmt
-  = use tblRefs >>= makeList "tbl" opts lotItemTemplate lotTitle xs
-listOf opts (RawBlock fmt "\\listoflistings":xs)
-  | isLaTeXRawBlockFmt fmt
-  = use lstRefs >>= makeList "lst" opts lolItemTemplate lolTitle xs
-listOf _ x = return x
+listOf :: [Block] -> WS [Block]
+listOf blocks = asks (isLatexFormat . outFormat) >>= \case
+  True -> pure blocks
+  False -> case blocks of
+    (RawBlock fmt "\\listoffigures":xs)
+      | isLaTeXRawBlockFmt fmt
+      -> use imgRefs >>= makeList "fig" lofItemTemplate lofTitle xs
+    (RawBlock fmt "\\listoftables":xs)
+      | isLaTeXRawBlockFmt fmt
+      -> use tblRefs >>= makeList "tbl" lotItemTemplate lotTitle xs
+    (RawBlock fmt "\\listoflistings":xs)
+      | isLaTeXRawBlockFmt fmt
+      -> use lstRefs >>= makeList "lst" lolItemTemplate lolTitle xs
+    _ -> pure blocks
 
 makeList
   :: T.Text
-  -> Options
-  -> (Options
-  -> BlockTemplate)
-  -> (Options
-  -> [Block])
+  -> (Options -> BlockTemplate)
+  -> (Options -> [Block])
   -> [Block]
   -> M.Map T.Text RefRec
   -> WS [Block]
-makeList pfx o tf titlef xs refs =
-  pure $ titlef o <> (Div ("", ["list", "list-of-" <> pfx], []) items : xs)
+makeList pfx tf titlef xs refs = do
+  o <- ask
+  pure $ titlef o <> (Div ("", ["list", "list-of-" <> pfx], []) (items o) : xs)
   where
-    items = fromMaybe items'$ pure <$> mergeList Nothing [] items'
-    items' = concatMap (itemChap . snd) refsSorted
+    items o = let is = items' o in fromMaybe is $ pure <$> mergeList Nothing [] is
+    items' o = concatMap (itemChap o . snd) refsSorted
     mergeList Nothing acc (OrderedList style item : ys) =
       mergeList (Just $ OrderedList style) (item <> acc) ys
     mergeList Nothing acc (BulletList item : ys) =
@@ -78,22 +80,22 @@
       (_,RefRec{refIndex=i, refSubfigure=si})
       (_,RefRec{refIndex=j, refSubfigure=sj})
       = compare (i, si) (j, sj)
-    itemChap :: RefRec -> [Block]
-    itemChap ref@RefRec{..} = applyTemplate (numWithChap ref) refTitle (tf o)
-    numWithChap :: RefRec -> [Inline]
-    numWithChap RefRec{..} = case refSubfigure of
+    itemChap :: Options -> RefRec -> [Block]
+    itemChap o ref@RefRec{..} = applyTemplate (numWithChap o ref) refTitle (tf o)
+    numWithChap :: Options -> RefRec -> [Inline]
+    numWithChap Options{..} RefRec{..} = case refSubfigure of
       Nothing ->
         let vars = M.fromDistinctAscList
-              [ ("i", chapPrefix (chapDelim o) refIndex)
+              [ ("i", chapPrefix chapDelim refIndex)
               , ("suf", mempty)
               , ("t", refTitle)
               ]
-        in applyTemplate' vars $ refIndexTemplate o pfx
+        in applyTemplate' vars $ refIndexTemplate pfx
       Just s ->
         let vars = M.fromDistinctAscList
-              [ ("i", chapPrefix (chapDelim o) refIndex)
-              , ("s", chapPrefix (chapDelim o) s)
+              [ ("i", chapPrefix chapDelim refIndex)
+              , ("s", chapPrefix chapDelim s)
               , ("suf", mempty)
               , ("t", refTitle)
               ]
-        in applyTemplate' vars $ subfigureRefIndexTemplate o
+        in applyTemplate' vars subfigureRefIndexTemplate
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Monad.hs b/lib-internal/Text/Pandoc/CrossRef/References/Monad.hs
new file mode 100644
--- /dev/null
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Monad.hs
@@ -0,0 +1,31 @@
+{-
+pandoc-crossref is a pandoc filter for numbering figures,
+equations, tables and cross-references to them.
+Copyright (C) 2015  Nikolay Yakimov <root@livid.pp.ru>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-}
+
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Text.Pandoc.CrossRef.References.Monad where
+
+import Control.Monad.State
+import Control.Monad.Reader
+import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.Util.Options
+
+--state monad
+newtype WS a = WS { runWS :: ReaderT Options (State References) a }
+  deriving (Functor, Applicative, Monad, MonadReader Options, MonadState References)
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Refs.hs b/lib-internal/Text/Pandoc/CrossRef/References/Refs.hs
--- a/lib-internal/Text/Pandoc/CrossRef/References/Refs.hs
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Refs.hs
@@ -22,7 +22,7 @@
 module Text.Pandoc.CrossRef.References.Refs (replaceRefs) where
 
 import Control.Arrow as A
-import Control.Monad.State hiding (get, modify)
+import Control.Monad.Reader
 import Data.Function
 import Data.List
 import qualified Data.List.HT as HT
@@ -35,20 +35,23 @@
 import Debug.Trace
 import Lens.Micro.Mtl
 import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
 import Text.Pandoc.CrossRef.Util.Options
 import Text.Pandoc.CrossRef.Util.Template
 import Text.Pandoc.CrossRef.Util.Util
 
-replaceRefs :: Options -> [Inline] -> WS [Inline]
-replaceRefs opts (Cite cits _:xs)
-  = toList . (<> fromList xs) . intercalate' (text ", ") . map fromList <$> mapM replaceRefs' (groupBy eqPrefix cits)
+replaceRefs :: [Inline] -> WS [Inline]
+replaceRefs (Cite cits _:xs) = do
+  opts <- ask :: WS Options
+  toList . (<> fromList xs) . intercalate' (text ", ") . map fromList <$> mapM (replaceRefs' opts) (groupBy eqPrefix cits)
   where
     eqPrefix a b = uncurry (==) $
       (fmap uncapitalizeFirst . getLabelPrefix . citationId) <***> (a,b)
     (<***>) = join (***)
-    replaceRefs' cits'
+    replaceRefs' :: Options -> [Citation] -> WS [Inline]
+    replaceRefs' opts cits'
       | Just prefix <- allCitsPrefix cits'
-      = replaceRefs'' prefix opts cits'
+      = replaceRefs'' opts prefix cits'
       | otherwise = return [Cite cits' il']
         where
           il' = toList $
@@ -58,10 +61,11 @@
           citationToInlines c =
             fromList (citationPrefix c) <> text ("@" <> citationId c)
               <> fromList (citationSuffix c)
-    replaceRefs'' = case outFormat opts of
+    replaceRefs'' :: Options -> T.Text -> [Citation] -> WS [Inline]
+    replaceRefs'' opts = ($ opts) . flip $ case outFormat opts of
                     f | isLatexFormat f -> replaceRefsLatex
-                    _                      -> replaceRefsOther
-replaceRefs _ x = return x
+                    _                   -> replaceRefsOther
+replaceRefs x = return x
 
 -- accessors to state variables
 accMap :: M.Map T.Text ((RefMap -> Const RefMap RefMap) -> References -> Const RefMap References)
diff --git a/lib-internal/Text/Pandoc/CrossRef/References/Types.hs b/lib-internal/Text/Pandoc/CrossRef/References/Types.hs
--- a/lib-internal/Text/Pandoc/CrossRef/References/Types.hs
+++ b/lib-internal/Text/Pandoc/CrossRef/References/Types.hs
@@ -21,7 +21,6 @@
 {-# LANGUAGE TemplateHaskell #-}
 module Text.Pandoc.CrossRef.References.Types where
 
-import Control.Monad.State
 import Data.Default
 import qualified Data.Map as M
 import Data.Text (Text)
@@ -45,9 +44,6 @@
                              , _secRefs :: RefMap
                              , _curChap :: Index
                              } deriving (Show, Eq)
-
---state monad
-type WS a = State References a
 
 instance Default References where
   def = References n n n n n []
diff --git a/lib-internal/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs b/lib-internal/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs
--- a/lib-internal/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs
+++ b/lib-internal/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs
@@ -18,26 +18,31 @@
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 -}
 
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, LambdaCase #-}
 module Text.Pandoc.CrossRef.Util.CodeBlockCaptions
     (
     mkCodeBlockCaptions
     ) where
 
+import Control.Monad.Reader (ask)
 import Data.List (stripPrefix)
 import Data.Maybe (fromMaybe)
 import qualified Data.Text as T
-import Text.Pandoc.CrossRef.References.Types
+import Text.Pandoc.CrossRef.References.Monad
 import Text.Pandoc.CrossRef.Util.Options
 import Text.Pandoc.CrossRef.Util.Util
 import Text.Pandoc.Definition
 
-mkCodeBlockCaptions :: Options -> [Block] -> WS [Block]
-mkCodeBlockCaptions opts x@(cb@(CodeBlock _ _):p@(Para _):xs)
-  = return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs
-mkCodeBlockCaptions opts x@(p@(Para _):cb@(CodeBlock _ _):xs)
-  = return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs
-mkCodeBlockCaptions _ x = return x
+mkCodeBlockCaptions :: [Block] -> WS [Block]
+mkCodeBlockCaptions = \case
+  x@(cb@CodeBlock{}:p@Para{}:xs) -> go x p cb xs
+  x@(p@Para{}:cb@CodeBlock{}:xs) -> go x p cb xs
+  x -> pure x
+  where
+    go :: [Block] -> Block -> Block -> [Block] -> WS [Block]
+    go x p cb xs = do
+      opts <- ask
+      return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs
 
 orderAgnostic :: Options -> [Block] -> Maybe [Block]
 orderAgnostic opts (Para ils:CodeBlock (label,classes,attrs) code:xs)
diff --git a/lib/Text/Pandoc/CrossRef.hs b/lib/Text/Pandoc/CrossRef.hs
--- a/lib/Text/Pandoc/CrossRef.hs
+++ b/lib/Text/Pandoc/CrossRef.hs
@@ -85,6 +85,7 @@
 import Text.Pandoc
 
 import Text.Pandoc.CrossRef.References
+import Text.Pandoc.CrossRef.References.Monad
 import Text.Pandoc.CrossRef.Util.CodeBlockCaptions
 import Text.Pandoc.CrossRef.Util.ModifyMeta
 import Text.Pandoc.CrossRef.Util.Options as O
@@ -108,11 +109,11 @@
   opts <- R.asks creOptions
   let
     doWalk =
-      bottomUpM (mkCodeBlockCaptions opts) blocks
-      >>= replaceAll opts
-      >>= bottomUpM (replaceRefs opts)
-      >>= bottomUpM (listOf opts)
-    (result, st) = runState doWalk def
+      bottomUpM mkCodeBlockCaptions blocks
+      >>= replaceAll
+      >>= bottomUpM replaceRefs
+      >>= bottomUpM listOf
+    (result, st) = flip runState def $ flip R.runReaderT opts $ runWS doWalk
   st `seq` return result
 
 {- | Modifies metadata for LaTeX output, adding header-includes instructions
diff --git a/pandoc-crossref.cabal b/pandoc-crossref.cabal
--- a/pandoc-crossref.cabal
+++ b/pandoc-crossref.cabal
@@ -1,11 +1,11 @@
 cabal-version: 2.0
 
--- This file has been generated from package.yaml by hpack version 0.34.4.
+-- This file has been generated from package.yaml by hpack version 0.35.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:           pandoc-crossref
-version:        0.3.14.0
+version:        0.3.15.0
 synopsis:       Pandoc filter for cross-references
 description:    pandoc-crossref is a pandoc filter for numbering figures, equations, tables and cross-references to them.
 category:       Text
@@ -127,9 +127,9 @@
   build-depends:
       base >=4.11 && <5
     , mtl >=1.1 && <2.4
-    , pandoc >=2.18 && <2.20
+    , pandoc ==3.0.*
     , pandoc-crossref-internal
-    , pandoc-types >=1.22.2 && <1.23
+    , pandoc-types
     , text >=1.2.2 && <2.1
   default-language: Haskell2010
 
@@ -138,7 +138,14 @@
       Text.Numeral.Roman
       Text.Pandoc.CrossRef.References
       Text.Pandoc.CrossRef.References.Blocks
+      Text.Pandoc.CrossRef.References.Blocks.CodeBlock
+      Text.Pandoc.CrossRef.References.Blocks.Header
+      Text.Pandoc.CrossRef.References.Blocks.Math
+      Text.Pandoc.CrossRef.References.Blocks.Subfigures
+      Text.Pandoc.CrossRef.References.Blocks.Table
+      Text.Pandoc.CrossRef.References.Blocks.Util
       Text.Pandoc.CrossRef.References.List
+      Text.Pandoc.CrossRef.References.Monad
       Text.Pandoc.CrossRef.References.Refs
       Text.Pandoc.CrossRef.References.Types
       Text.Pandoc.CrossRef.Util.CodeBlockCaptions
@@ -163,8 +170,8 @@
     , microlens-mtl >=0.2.0.1 && <0.3.0.0
     , microlens-th >=0.4.3.10 && <0.5.0.0
     , mtl >=1.1 && <2.3
-    , pandoc >=2.18 && <2.20
-    , pandoc-types >=1.22.2 && <1.23
+    , pandoc ==3.0.*
+    , pandoc-types
     , syb >=0.4 && <0.8
     , template-haskell >=2.7.0.0 && <3.0.0.0
     , text >=1.2.2 && <2.1
@@ -184,9 +191,9 @@
     , gitrev >=1.3.1 && <1.4
     , open-browser ==0.2.*
     , optparse-applicative >=0.13 && <0.18
-    , pandoc >=2.18 && <2.20
+    , pandoc ==3.0.*
     , pandoc-crossref
-    , pandoc-types >=1.22.2 && <1.23
+    , pandoc-types
     , template-haskell >=2.7.0.0 && <3.0.0.0
     , temporary >=1.2 && <1.4
     , text >=1.2.2 && <2.1
@@ -198,18 +205,20 @@
   hs-source-dirs:
       test
   ghc-options: -Wall -fno-warn-unused-do-bind -threaded
+  build-tool-depends:
+      pandoc-cli:pandoc
   build-depends:
       base >=4.11 && <5
     , directory >=1 && <1.4
     , filepath >=1.1 && <1.5
     , hspec >=2.4.4 && <3
-    , pandoc >=2.18 && <2.20
+    , pandoc ==3.0.*
     , pandoc-crossref
-    , pandoc-types >=1.22.2 && <1.23
+    , pandoc-types
     , text >=1.2.2 && <2.1
+  default-language: Haskell2010
   if flag(enable_flaky_tests)
     cpp-options: -DFLAKY
-  default-language: Haskell2010
 
 test-suite test-pandoc-crossref
   type: exitcode-stdio-1.0
@@ -229,14 +238,14 @@
     , hspec >=2.4.4 && <3
     , microlens >=0.4.12.0 && <0.5.0.0
     , mtl >=1.1 && <2.3
-    , pandoc >=2.18 && <2.20
+    , pandoc ==3.0.*
     , pandoc-crossref
     , pandoc-crossref-internal
-    , pandoc-types >=1.22.2 && <1.23
+    , pandoc-types
     , text >=1.2.2 && <2.1
+  default-language: Haskell2010
   if flag(enable_flaky_tests)
     cpp-options: -DFLAKY
-  default-language: Haskell2010
 
 benchmark simple
   type: exitcode-stdio-1.0
@@ -249,8 +258,8 @@
   build-depends:
       base >=4.11 && <5
     , criterion >=1.5.9.0 && <1.7
-    , pandoc >=2.18 && <2.20
+    , pandoc ==3.0.*
     , pandoc-crossref
-    , pandoc-types >=1.22.2 && <1.23
+    , pandoc-types
     , text >=1.2.2 && <2.1
   default-language: Haskell2010
diff --git a/test/demo-chapters.inc b/test/demo-chapters.inc
--- a/test/demo-chapters.inc
+++ b/test/demo-chapters.inc
@@ -67,20 +67,28 @@
       , Space
       , Str "fig.\160\&1"
       ]
-  , Para
-      [ Image
-          ( "fig:figure0" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "1:"
-          , Space
-          , Str "A"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure0" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "1:"
+             , Space
+             , Str "A"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "A" , Space , Str "figure" ]
+              ( "img1.jpg" , "" )
           ]
-          ( "img1.jpg" , "fig:" )
       ]
   , Para
       [ Str "There"
@@ -292,94 +300,138 @@
       1
       ( "sec:sec1" , [] , [] )
       [ Str "Chapter" , Space , Str "1." , Space , Str "Figures" ]
-  , Para
-      [ Image
-          ( "fig:figure1" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "1.1:"
-          , Space
-          , Str "First"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure1" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "1.1:"
+             , Space
+             , Str "First"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "First" , Space , Str "figure" ]
+              ( "img1.jpg" , "" )
           ]
-          ( "img1.jpg" , "fig:" )
       ]
-  , Para
-      [ Image
-          ( "fig:figure2" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "1.2:"
-          , Space
-          , Str "Second"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure2" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "1.2:"
+             , Space
+             , Str "Second"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "Second" , Space , Str "figure" ]
+              ( "img2.jpg" , "" )
           ]
-          ( "img2.jpg" , "fig:" )
       ]
-  , Para
-      [ Image
-          ( "fig:figure3" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "1.3:"
-          , Space
-          , Str "Third"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure3" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "1.3:"
+             , Space
+             , Str "Third"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "Third" , Space , Str "figure" ]
+              ( "img3.jpg" , "" )
           ]
-          ( "img3.jpg" , "fig:" )
       ]
-  , Para
-      [ Image
-          ( "" , [] , [] )
-          [ Str "Unlabelled" , Space , Str "image" ]
-          ( "img1.jpg" , "fig:" )
+  , Figure
+      ( "" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain [ Str "Unlabelled" , Space , Str "image" ] ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "Unlabelled" , Space , Str "image" ]
+              ( "img1.jpg" , "" )
+          ]
       ]
-  , Div
+  , Figure
       ( "fig:subfigures" , [ "subfigures" ] , [] )
-      [ Para
-          [ Image ( "" , [] , [] ) [ Str "a" ] ( "img1.jpg" , "fig:" )
-          ]
-      , Para
-          [ Image
-              ( "fig:subfigureB" , [] , [] )
-              [ Str "b" ]
-              ( "img1.jpg" , "fig:" )
+      (Caption
+         Nothing
+         [ Para
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "1.4:"
+             , Space
+             , Str "Subfigures"
+             , Space
+             , Str "caption."
+             , Space
+             , Str "a"
+             , Space
+             , Str "\8212"
+             , Space
+             , Str "Subfigure"
+             , Space
+             , Str "a,"
+             , Space
+             , Str "b"
+             , Space
+             , Str "\8212"
+             , Space
+             , Str "Subfigure"
+             , Space
+             , Str "b"
+             ]
+         ])
+      [ Figure
+          ( "" , [] , [] )
+          (Caption Nothing [ Plain [ Str "a" ] ])
+          [ Plain
+              [ Image
+                  ( "" , [] , [] )
+                  [ Str "Subfigure" , Space , Str "a" ]
+                  ( "img1.jpg" , "" )
+              ]
           ]
-      , Para
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "1.4:"
-          , Space
-          , Str "Subfigures"
-          , Space
-          , Str "caption."
-          , Space
-          , Str "a"
-          , Space
-          , Str "\8212"
-          , Space
-          , Str "Subfigure"
-          , Space
-          , Str "a,"
-          , Space
-          , Str "b"
-          , Space
-          , Str "\8212"
-          , Space
-          , Str "Subfigure"
-          , Space
-          , Str "b"
+      , Figure
+          ( "fig:subfigureB" , [] , [] )
+          (Caption Nothing [ Plain [ Str "b" ] ])
+          [ Plain
+              [ Image
+                  ( "" , [] , [] )
+                  [ Str "Subfigure" , Space , Str "b" ]
+                  ( "img1.jpg" , "" )
+              ]
           ]
       ]
   , Header
diff --git a/test/demo.inc b/test/demo.inc
--- a/test/demo.inc
+++ b/test/demo.inc
@@ -67,20 +67,28 @@
       , Space
       , Str "fig.\160\&1"
       ]
-  , Para
-      [ Image
-          ( "fig:figure0" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "1:"
-          , Space
-          , Str "A"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure0" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "1:"
+             , Space
+             , Str "A"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "A" , Space , Str "figure" ]
+              ( "img1.jpg" , "" )
           ]
-          ( "img1.jpg" , "fig:" )
       ]
   , Para
       [ Str "There"
@@ -292,94 +300,138 @@
       1
       ( "sec:sec1" , [] , [] )
       [ Str "Chapter" , Space , Str "1." , Space , Str "Figures" ]
-  , Para
-      [ Image
-          ( "fig:figure1" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "2:"
-          , Space
-          , Str "First"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure1" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "2:"
+             , Space
+             , Str "First"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "First" , Space , Str "figure" ]
+              ( "img1.jpg" , "" )
           ]
-          ( "img1.jpg" , "fig:" )
       ]
-  , Para
-      [ Image
-          ( "fig:figure2" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "3:"
-          , Space
-          , Str "Second"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure2" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "3:"
+             , Space
+             , Str "Second"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "Second" , Space , Str "figure" ]
+              ( "img2.jpg" , "" )
           ]
-          ( "img2.jpg" , "fig:" )
       ]
-  , Para
-      [ Image
-          ( "fig:figure3" , [] , [] )
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "4:"
-          , Space
-          , Str "Third"
-          , Space
-          , Str "figure"
+  , Figure
+      ( "fig:figure3" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "4:"
+             , Space
+             , Str "Third"
+             , Space
+             , Str "figure"
+             ]
+         ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "Third" , Space , Str "figure" ]
+              ( "img3.jpg" , "" )
           ]
-          ( "img3.jpg" , "fig:" )
       ]
-  , Para
-      [ Image
-          ( "" , [] , [] )
-          [ Str "Unlabelled" , Space , Str "image" ]
-          ( "img1.jpg" , "fig:" )
+  , Figure
+      ( "" , [] , [] )
+      (Caption
+         Nothing
+         [ Plain [ Str "Unlabelled" , Space , Str "image" ] ])
+      [ Plain
+          [ Image
+              ( "" , [] , [] )
+              [ Str "Unlabelled" , Space , Str "image" ]
+              ( "img1.jpg" , "" )
+          ]
       ]
-  , Div
+  , Figure
       ( "fig:subfigures" , [ "subfigures" ] , [] )
-      [ Para
-          [ Image ( "" , [] , [] ) [ Str "a" ] ( "img1.jpg" , "fig:" )
-          ]
-      , Para
-          [ Image
-              ( "fig:subfigureB" , [] , [] )
-              [ Str "b" ]
-              ( "img1.jpg" , "fig:" )
+      (Caption
+         Nothing
+         [ Para
+             [ Str "Figure"
+             , Space
+             , Str "#"
+             , Space
+             , Str "5:"
+             , Space
+             , Str "Subfigures"
+             , Space
+             , Str "caption."
+             , Space
+             , Str "a"
+             , Space
+             , Str "\8212"
+             , Space
+             , Str "Subfigure"
+             , Space
+             , Str "a,"
+             , Space
+             , Str "b"
+             , Space
+             , Str "\8212"
+             , Space
+             , Str "Subfigure"
+             , Space
+             , Str "b"
+             ]
+         ])
+      [ Figure
+          ( "" , [] , [] )
+          (Caption Nothing [ Plain [ Str "a" ] ])
+          [ Plain
+              [ Image
+                  ( "" , [] , [] )
+                  [ Str "Subfigure" , Space , Str "a" ]
+                  ( "img1.jpg" , "" )
+              ]
           ]
-      , Para
-          [ Str "Figure"
-          , Space
-          , Str "#"
-          , Space
-          , Str "5:"
-          , Space
-          , Str "Subfigures"
-          , Space
-          , Str "caption."
-          , Space
-          , Str "a"
-          , Space
-          , Str "\8212"
-          , Space
-          , Str "Subfigure"
-          , Space
-          , Str "a,"
-          , Space
-          , Str "b"
-          , Space
-          , Str "\8212"
-          , Space
-          , Str "Subfigure"
-          , Space
-          , Str "b"
+      , Figure
+          ( "fig:subfigureB" , [] , [] )
+          (Caption Nothing [ Plain [ Str "b" ] ])
+          [ Plain
+              [ Image
+                  ( "" , [] , [] )
+                  [ Str "Subfigure" , Space , Str "b" ]
+                  ( "img1.jpg" , "" )
+              ]
           ]
       ]
   , Header
diff --git a/test/m2m/emptyChapterLabels/expect.md b/test/m2m/emptyChapterLabels/expect.md
--- a/test/m2m/emptyChapterLabels/expect.md
+++ b/test/m2m/emptyChapterLabels/expect.md
@@ -2,7 +2,13 @@
 
 ## 1 Subsection {#sec:subsection label=""}
 
-![Figure 1: Figure1](./image.png){#fig:figure1}
+::: {#fig:figure1 .figure}
+![Figure1](./image.png)
+
+::: caption
+Figure 1: Figure1
+:::
+:::
 
 ### 1.1 Subsubsection {#sec:subsubsection}
 
diff --git a/test/m2m/label-precedence/expect.md b/test/m2m/label-precedence/expect.md
--- a/test/m2m/label-precedence/expect.md
+++ b/test/m2m/label-precedence/expect.md
@@ -2,13 +2,25 @@
 
 text
 
-![Figure α: A figure](image.png){#fig:fig1}
+::: {#fig:fig1 .figure}
+![A figure](image.png)
 
+::: caption
+Figure α: A figure
+:::
+:::
+
 ## \*.A Subsection {#subsection}
 
 other text
 
-![Figure +: A figure with custom label](image.png){#fig:fig2 label="+"}
+::: {#fig:fig2 .figure label="+"}
+![A figure with custom label](image.png){label="+"}
+
+::: caption
+Figure +: A figure with custom label
+:::
+:::
 
 ### \*.A.A Subsubsection {#subsubsection}
 
diff --git a/test/m2m/listOfTemplates-buillet-list/expect.md b/test/m2m/listOfTemplates-buillet-list/expect.md
--- a/test/m2m/listOfTemplates-buillet-list/expect.md
+++ b/test/m2m/listOfTemplates-buillet-list/expect.md
@@ -1,20 +1,74 @@
-![Figure 1: 1](fig1.png){#fig:1}
+::: {#fig:1 .figure}
+![1](fig1.png)
 
-![Figure 2: 2](fig2.png){#fig:2}
+::: caption
+Figure 1: 1
+:::
+:::
 
-![Figure 3: 3](fig3.png){#fig:3}
+::: {#fig:2 .figure}
+![2](fig2.png)
 
-![Figure 4: 4](fig4.png){#fig:4}
+::: caption
+Figure 2: 2
+:::
+:::
 
-![Figure 5: 5](fig5.png){#fig:5}
+::: {#fig:3 .figure}
+![3](fig3.png)
 
-![Figure 6: 6](fig6.png){#fig:6}
+::: caption
+Figure 3: 3
+:::
+:::
 
-![Figure 7: 7](fig7.png){#fig:7}
+::: {#fig:4 .figure}
+![4](fig4.png)
 
-![Figure 8: 8](fig8.png){#fig:8}
+::: caption
+Figure 4: 4
+:::
+:::
 
-![Figure 9: 9](fig9.png){#fig:9}
+::: {#fig:5 .figure}
+![5](fig5.png)
+
+::: caption
+Figure 5: 5
+:::
+:::
+
+::: {#fig:6 .figure}
+![6](fig6.png)
+
+::: caption
+Figure 6: 6
+:::
+:::
+
+::: {#fig:7 .figure}
+![7](fig7.png)
+
+::: caption
+Figure 7: 7
+:::
+:::
+
+::: {#fig:8 .figure}
+![8](fig8.png)
+
+::: caption
+Figure 8: 8
+:::
+:::
+
+::: {#fig:9 .figure}
+![9](fig9.png)
+
+::: caption
+Figure 9: 9
+:::
+:::
 
 # List of Figures
 
diff --git a/test/m2m/listOfTemplates-ord-list/expect.md b/test/m2m/listOfTemplates-ord-list/expect.md
--- a/test/m2m/listOfTemplates-ord-list/expect.md
+++ b/test/m2m/listOfTemplates-ord-list/expect.md
@@ -1,20 +1,74 @@
-![Figure 1: 1](fig1.png){#fig:1}
+::: {#fig:1 .figure}
+![1](fig1.png)
 
-![Figure 2: 2](fig2.png){#fig:2}
+::: caption
+Figure 1: 1
+:::
+:::
 
-![Figure 3: 3](fig3.png){#fig:3}
+::: {#fig:2 .figure}
+![2](fig2.png)
 
-![Figure 4: 4](fig4.png){#fig:4}
+::: caption
+Figure 2: 2
+:::
+:::
 
-![Figure 5: 5](fig5.png){#fig:5}
+::: {#fig:3 .figure}
+![3](fig3.png)
 
-![Figure 6: 6](fig6.png){#fig:6}
+::: caption
+Figure 3: 3
+:::
+:::
 
-![Figure 7: 7](fig7.png){#fig:7}
+::: {#fig:4 .figure}
+![4](fig4.png)
 
-![Figure 8: 8](fig8.png){#fig:8}
+::: caption
+Figure 4: 4
+:::
+:::
 
-![Figure 9: 9](fig9.png){#fig:9}
+::: {#fig:5 .figure}
+![5](fig5.png)
+
+::: caption
+Figure 5: 5
+:::
+:::
+
+::: {#fig:6 .figure}
+![6](fig6.png)
+
+::: caption
+Figure 6: 6
+:::
+:::
+
+::: {#fig:7 .figure}
+![7](fig7.png)
+
+::: caption
+Figure 7: 7
+:::
+:::
+
+::: {#fig:8 .figure}
+![8](fig8.png)
+
+::: caption
+Figure 8: 8
+:::
+:::
+
+::: {#fig:9 .figure}
+![9](fig9.png)
+
+::: caption
+Figure 9: 9
+:::
+:::
 
 # List of Figures
 
diff --git a/test/m2m/listOfTemplates/expect.md b/test/m2m/listOfTemplates/expect.md
--- a/test/m2m/listOfTemplates/expect.md
+++ b/test/m2m/listOfTemplates/expect.md
@@ -1,20 +1,74 @@
-![Figure 1: 1](fig1.png){#fig:1}
+::: {#fig:1 .figure}
+![1](fig1.png)
 
-![Figure 2: 2](fig2.png){#fig:2}
+::: caption
+Figure 1: 1
+:::
+:::
 
-![Figure 3: 3](fig3.png){#fig:3}
+::: {#fig:2 .figure}
+![2](fig2.png)
 
-![Figure 4: 4](fig4.png){#fig:4}
+::: caption
+Figure 2: 2
+:::
+:::
 
-![Figure 5: 5](fig5.png){#fig:5}
+::: {#fig:3 .figure}
+![3](fig3.png)
 
-![Figure 6: 6](fig6.png){#fig:6}
+::: caption
+Figure 3: 3
+:::
+:::
 
-![Figure 7: 7](fig7.png){#fig:7}
+::: {#fig:4 .figure}
+![4](fig4.png)
 
-![Figure 8: 8](fig8.png){#fig:8}
+::: caption
+Figure 4: 4
+:::
+:::
 
-![Figure 9: 9](fig9.png){#fig:9}
+::: {#fig:5 .figure}
+![5](fig5.png)
+
+::: caption
+Figure 5: 5
+:::
+:::
+
+::: {#fig:6 .figure}
+![6](fig6.png)
+
+::: caption
+Figure 6: 6
+:::
+:::
+
+::: {#fig:7 .figure}
+![7](fig7.png)
+
+::: caption
+Figure 7: 7
+:::
+:::
+
+::: {#fig:8 .figure}
+![8](fig8.png)
+
+::: caption
+Figure 8: 8
+:::
+:::
+
+::: {#fig:9 .figure}
+![9](fig9.png)
+
+::: caption
+Figure 9: 9
+:::
+:::
 
 ::: {#lst:code1 .listing .haskell}
 Listing 1: Listing caption 1
diff --git a/test/m2m/listOfTemplates/expect.tex b/test/m2m/listOfTemplates/expect.tex
--- a/test/m2m/listOfTemplates/expect.tex
+++ b/test/m2m/listOfTemplates/expect.tex
@@ -135,32 +135,34 @@
 \hypertarget{tbl:mytable}{}
 \begin{longtable}[]{@{}lll@{}}
 \caption{\label{tbl:mytable}My table}\tabularnewline
-\toprule()
+\toprule\noalign{}
 a & b & c \\
-\midrule()
+\midrule\noalign{}
 \endfirsthead
-\toprule()
+\toprule\noalign{}
 a & b & c \\
-\midrule()
+\midrule\noalign{}
 \endhead
+\bottomrule\noalign{}
+\endlastfoot
 1 & 2 & 3 \\
 4 & 5 & 6 \\
-\bottomrule()
 \end{longtable}
 
 \hypertarget{tbl:1}{}
 \begin{longtable}[]{@{}ll@{}}
 \caption{\label{tbl:1}Table}\tabularnewline
-\toprule()
+\toprule\noalign{}
 a & b \\
-\midrule()
+\midrule\noalign{}
 \endfirsthead
-\toprule()
+\toprule\noalign{}
 a & b \\
-\midrule()
+\midrule\noalign{}
 \endhead
+\bottomrule\noalign{}
+\endlastfoot
 1 & 2 \\
-\bottomrule()
 \end{longtable}
 
 \listoffigures
diff --git a/test/m2m/loxItemTitle/expect.md b/test/m2m/loxItemTitle/expect.md
--- a/test/m2m/loxItemTitle/expect.md
+++ b/test/m2m/loxItemTitle/expect.md
@@ -1,20 +1,74 @@
-![Figure 1: 1](fig1.png){#fig:1}
+::: {#fig:1 .figure}
+![1](fig1.png)
 
-![Figure 2: 2](fig2.png){#fig:2}
+::: caption
+Figure 1: 1
+:::
+:::
 
-![Figure 3: 3](fig3.png){#fig:3}
+::: {#fig:2 .figure}
+![2](fig2.png)
 
-![Figure 4: 4](fig4.png){#fig:4}
+::: caption
+Figure 2: 2
+:::
+:::
 
-![Figure 5: 5](fig5.png){#fig:5}
+::: {#fig:3 .figure}
+![3](fig3.png)
 
-![Figure 6: 6](fig6.png){#fig:6}
+::: caption
+Figure 3: 3
+:::
+:::
 
-![Figure 7: 7](fig7.png){#fig:7}
+::: {#fig:4 .figure}
+![4](fig4.png)
 
-![Figure 8: 8](fig8.png){#fig:8}
+::: caption
+Figure 4: 4
+:::
+:::
 
-![Figure 9: 9](fig9.png){#fig:9}
+::: {#fig:5 .figure}
+![5](fig5.png)
+
+::: caption
+Figure 5: 5
+:::
+:::
+
+::: {#fig:6 .figure}
+![6](fig6.png)
+
+::: caption
+Figure 6: 6
+:::
+:::
+
+::: {#fig:7 .figure}
+![7](fig7.png)
+
+::: caption
+Figure 7: 7
+:::
+:::
+
+::: {#fig:8 .figure}
+![8](fig8.png)
+
+::: caption
+Figure 8: 8
+:::
+:::
+
+::: {#fig:9 .figure}
+![9](fig9.png)
+
+::: caption
+Figure 9: 9
+:::
+:::
 
 ::: {#lst:code1 .listing .haskell}
 Listing 1: Listing caption 1
diff --git a/test/m2m/loxItemTitle/expect.tex b/test/m2m/loxItemTitle/expect.tex
--- a/test/m2m/loxItemTitle/expect.tex
+++ b/test/m2m/loxItemTitle/expect.tex
@@ -135,32 +135,34 @@
 \hypertarget{tbl:mytable}{}
 \begin{longtable}[]{@{}lll@{}}
 \caption{\label{tbl:mytable}My table}\tabularnewline
-\toprule()
+\toprule\noalign{}
 a & b & c \\
-\midrule()
+\midrule\noalign{}
 \endfirsthead
-\toprule()
+\toprule\noalign{}
 a & b & c \\
-\midrule()
+\midrule\noalign{}
 \endhead
+\bottomrule\noalign{}
+\endlastfoot
 1 & 2 & 3 \\
 4 & 5 & 6 \\
-\bottomrule()
 \end{longtable}
 
 \hypertarget{tbl:1}{}
 \begin{longtable}[]{@{}ll@{}}
 \caption{\label{tbl:1}Table}\tabularnewline
-\toprule()
+\toprule\noalign{}
 a & b \\
-\midrule()
+\midrule\noalign{}
 \endfirsthead
-\toprule()
+\toprule\noalign{}
 a & b \\
-\midrule()
+\midrule\noalign{}
 \endhead
+\bottomrule\noalign{}
+\endlastfoot
 1 & 2 \\
-\bottomrule()
 \end{longtable}
 
 \listoffigures
diff --git a/test/m2m/secLabels/expect.md b/test/m2m/secLabels/expect.md
--- a/test/m2m/secLabels/expect.md
+++ b/test/m2m/secLabels/expect.md
@@ -2,7 +2,13 @@
 
 ## a.a Second Level Section {#second-level-section}
 
-![Figure a: my figure](myfig.png){#fig:myfig}
+::: {#fig:myfig .figure}
+![my figure](myfig.png)
+
+::: caption
+Figure a: my figure
+:::
+:::
 
 ## a.b Other Second Level Section {#other-second-level-section}
 
diff --git a/test/m2m/secLabels/expect.tex b/test/m2m/secLabels/expect.tex
--- a/test/m2m/secLabels/expect.tex
+++ b/test/m2m/secLabels/expect.tex
@@ -19,15 +19,16 @@
 \hypertarget{tbl:mytable}{}
 \begin{longtable}[]{@{}lll@{}}
 \caption{\label{tbl:mytable}My table}\tabularnewline
-\toprule()
+\toprule\noalign{}
 a & b & c \\
-\midrule()
+\midrule\noalign{}
 \endfirsthead
-\toprule()
+\toprule\noalign{}
 a & b & c \\
-\midrule()
+\midrule\noalign{}
 \endhead
+\bottomrule\noalign{}
+\endlastfoot
 1 & 2 & 3 \\
 4 & 5 & 6 \\
-\bottomrule()
 \end{longtable}
diff --git a/test/m2m/setLabelAttribute/expect.md b/test/m2m/setLabelAttribute/expect.md
--- a/test/m2m/setLabelAttribute/expect.md
+++ b/test/m2m/setLabelAttribute/expect.md
@@ -1,6 +1,12 @@
 # Section {#section label="1"}
 
-![Figure 1.1: Figure](./image.png){#fig:1 label="1.1"}
+::: {#fig:1 .figure label="1.1"}
+![Figure](./image.png)
+
+::: caption
+Figure 1.1: Figure
+:::
+:::
 
 [$$equation\qquad{(1.1)}$$]{#eq:1 label="(1.1)"}
 
diff --git a/test/m2m/setLabelAttribute/expect.tex b/test/m2m/setLabelAttribute/expect.tex
--- a/test/m2m/setLabelAttribute/expect.tex
+++ b/test/m2m/setLabelAttribute/expect.tex
@@ -14,16 +14,17 @@
 \hypertarget{tbl:1}{}
 \begin{longtable}[]{@{}ll@{}}
 \caption{\label{tbl:1}Table}\tabularnewline
-\toprule()
+\toprule\noalign{}
 a & b \\
-\midrule()
+\midrule\noalign{}
 \endfirsthead
-\toprule()
+\toprule\noalign{}
 a & b \\
-\midrule()
+\midrule\noalign{}
 \endhead
+\bottomrule\noalign{}
+\endlastfoot
 1 & 2 \\
-\bottomrule()
 \end{longtable}
 
 \begin{codelisting}
diff --git a/test/m2m/subfigures-ccsDelim/expect.md b/test/m2m/subfigures-ccsDelim/expect.md
--- a/test/m2m/subfigures-ccsDelim/expect.md
+++ b/test/m2m/subfigures-ccsDelim/expect.md
@@ -1,40 +1,95 @@
 You can define subfigures:
 
-::: {#fig:subfigures .subfigures}
-![a](fig1.png "fig:"){#fig:subfig1} ![b](fig2.png "fig:"){#fig:subfig2}
-![c](fig3.png "fig:")
+::: {#fig:subfigures .figure .subfigures}
+![a](fig1.png){#fig:subfig1} ![b](fig2.png){#fig:subfig2} ![c](fig3.png)
 
-![d](fig4.png "fig:"){#fig:subfig4} ![e](fig5.png "fig:")
-![f](fig6.png "fig:"){#fig:subfig6}
+![d](fig4.png){#fig:subfig4} ![e](fig5.png) ![f](fig6.png){#fig:subfig6}
 
-![g](fig7.png "fig:"){#fig:subfig7} ![h](fig8.png "fig:")
-![i](fig9.png "fig:"){#fig:subfig9}
+![g](fig7.png){#fig:subfig7} ![h](fig8.png) ![i](fig9.png){#fig:subfig9}
 
+::: caption
 Figure 1: Caption. a --- 1; b --- 2; c --- 3; d --- 4; e --- 5; f ---
 6; g --- 7; h --- 8; i --- 9
 :::
+:::
 
-::: {#fig:subfigures2 .subfigures}
-![a](fig1.png){#fig:subfig21}
+::: {#fig:subfigures2 .figure .subfigures}
+::: {#fig:subfig21 .figure}
+![1](fig1.png)
 
-![b](fig2.png){#fig:subfig22}
+::: caption
+a
+:::
+:::
 
-![c](fig3.png)
+::: {#fig:subfig22 .figure}
+![2](fig2.png)
 
-![d](fig4.png){#fig:subfig24}
+::: caption
+b
+:::
+:::
 
-![e](fig5.png)
+::: figure
+![3](fig3.png)
 
-![f](fig6.png){#fig:subfig26}
+::: caption
+c
+:::
+:::
 
-![g](fig7.png){#fig:subfig27}
+::: {#fig:subfig24 .figure}
+![4](fig4.png)
 
-![h](fig8.png)
+::: caption
+d
+:::
+:::
 
-![i](fig9.png){#fig:subfig29}
+::: figure
+![5](fig5.png)
 
+::: caption
+e
+:::
+:::
+
+::: {#fig:subfig26 .figure}
+![6](fig6.png)
+
+::: caption
+f
+:::
+:::
+
+::: {#fig:subfig27 .figure}
+![7](fig7.png)
+
+::: caption
+g
+:::
+:::
+
+::: figure
+![8](fig8.png)
+
+::: caption
+h
+:::
+:::
+
+::: {#fig:subfig29 .figure}
+![9](fig9.png)
+
+::: caption
+i
+:::
+:::
+
+::: caption
 Figure 2: Caption. a --- 1; b --- 2; c --- 3; d --- 4; e --- 5; f ---
 6; g --- 7; h --- 8; i --- 9
+:::
 :::
 
 Figures themselves can be referenced fig. 2, as well as individual
diff --git a/test/m2m/subfigures-grid/expect.md b/test/m2m/subfigures-grid/expect.md
--- a/test/m2m/subfigures-grid/expect.md
+++ b/test/m2m/subfigures-grid/expect.md
@@ -1,47 +1,126 @@
 You can define subfigures:
 
-::: {#fig:subfigures .subfigures}
+::: {#fig:subfigures .figure .subfigures}
 +:------------------:+:------------------:+:------------------:+
-| ![a](fig1          | ![b](fig2          | ![c](fig3.         |
-| .png){#fig:subfig1 | .png){#fig:subfig2 | png){width="100%"} |
-| width="100%"}      | width="100%"}      |                    |
+| ::                 | ::                 | ::: {.f            |
+| : {#fig:subfig1 .f | : {#fig:subfig2 .f | igure width="30%"} |
+| igure width="30%"} | igure width="30%"} | ![c](fig3.         |
+| ![a](fig1.         | ![b](fig2.         | png){width="100%"} |
+| png){width="100%"} | png){width="100%"} |                    |
+|                    |                    | ::: caption        |
+| ::: caption        | ::: caption        | c                  |
+| a                  | b                  | :::                |
+| :::                | :::                | :::                |
+| :::                | :::                |                    |
 +--------------------+--------------------+--------------------+
-| ![d](fig4          | ![e](fig5.         | ![f](fig6          |
-| .png){#fig:subfig4 | png){width="100%"} | .png){#fig:subfig6 |
-| width="100%"}      |                    | width="100%"}      |
+| ::                 | ::: {.f            | ::                 |
+| : {#fig:subfig4 .f | igure width="30%"} | : {#fig:subfig6 .f |
+| igure width="30%"} | ![e](fig5.         | igure width="30%"} |
+| ![d](fig4.         | png){width="100%"} | ![f](fig6.         |
+| png){width="100%"} |                    | png){width="100%"} |
+|                    | ::: caption        |                    |
+| ::: caption        | e                  | ::: caption        |
+| d                  | :::                | f                  |
+| :::                | :::                | :::                |
+| :::                |                    | :::                |
 +--------------------+--------------------+--------------------+
-| ![g](fig7          | ![h](fig8.         | ![i](fig9          |
-| .png){#fig:subfig7 | png){width="100%"} | .png){#fig:subfig9 |
-| width="100%"}      |                    | width="100%"}      |
+| ::                 | ::: {.f            | ::                 |
+| : {#fig:subfig7 .f | igure width="30%"} | : {#fig:subfig9 .f |
+| igure width="30%"} | ![h](fig8.         | igure width="30%"} |
+| ![g](fig7.         | png){width="100%"} | ![i](fig9.         |
+| png){width="100%"} |                    | png){width="100%"} |
+|                    | ::: caption        |                    |
+| ::: caption        | h                  | ::: caption        |
+| g                  | :::                | i                  |
+| :::                | :::                | :::                |
+| :::                |                    | :::                |
 +--------------------+--------------------+--------------------+
 
+::: caption
 Figure 1: Caption. a --- 1, b --- 2, c --- 3, d --- 4, e --- 5, f --- 6,
 g --- 7, h --- 8, i --- 9
 :::
+:::
 
-::: {#fig:subfigures2 .subfigures}
+::: {#fig:subfigures2 .figure .subfigures}
 +:--------------------------------------------------------------------:+
-| ![a](fig1.png){#fig:subfig21 width="100%"}                           |
+| ::: {#fig:subfig21 .figure}                                          |
+| ![1](fig1.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| a                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![b](fig2.png){#fig:subfig22 width="100%"}                           |
+| ::: {#fig:subfig22 .figure}                                          |
+| ![2](fig2.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| b                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![c](fig3.png){width="100%"}                                         |
+| ::: figure                                                           |
+| ![3](fig3.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| c                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![d](fig4.png){#fig:subfig24 width="100%"}                           |
+| ::: {#fig:subfig24 .figure}                                          |
+| ![4](fig4.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| d                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![e](fig5.png){width="100%"}                                         |
+| ::: figure                                                           |
+| ![5](fig5.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| e                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![f](fig6.png){#fig:subfig26 width="100%"}                           |
+| ::: {#fig:subfig26 .figure}                                          |
+| ![6](fig6.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| f                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![g](fig7.png){#fig:subfig27 width="100%"}                           |
+| ::: {#fig:subfig27 .figure}                                          |
+| ![7](fig7.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| g                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![h](fig8.png){width="100%"}                                         |
+| ::: figure                                                           |
+| ![8](fig8.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| h                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
-| ![i](fig9.png){#fig:subfig29 width="100%"}                           |
+| ::: {#fig:subfig29 .figure}                                          |
+| ![9](fig9.png)                                                       |
+|                                                                      |
+| ::: caption                                                          |
+| i                                                                    |
+| :::                                                                  |
+| :::                                                                  |
 +----------------------------------------------------------------------+
 
+::: caption
 Figure 2: Caption. a --- 1, b --- 2, c --- 3, d --- 4, e --- 5, f --- 6,
 g --- 7, h --- 8, i --- 9
+:::
 :::
 
 Figures themselves can be referenced fig. 2, as well as individual
diff --git a/test/m2m/subfigures/expect.md b/test/m2m/subfigures/expect.md
--- a/test/m2m/subfigures/expect.md
+++ b/test/m2m/subfigures/expect.md
@@ -1,40 +1,95 @@
 You can define subfigures:
 
-::: {#fig:subfigures .subfigures}
-![a](fig1.png "fig:"){#fig:subfig1} ![b](fig2.png "fig:"){#fig:subfig2}
-![c](fig3.png "fig:")
+::: {#fig:subfigures .figure .subfigures}
+![a](fig1.png){#fig:subfig1} ![b](fig2.png){#fig:subfig2} ![c](fig3.png)
 
-![d](fig4.png "fig:"){#fig:subfig4} ![e](fig5.png "fig:")
-![f](fig6.png "fig:"){#fig:subfig6}
+![d](fig4.png){#fig:subfig4} ![e](fig5.png) ![f](fig6.png){#fig:subfig6}
 
-![g](fig7.png "fig:"){#fig:subfig7} ![h](fig8.png "fig:")
-![i](fig9.png "fig:"){#fig:subfig9}
+![g](fig7.png){#fig:subfig7} ![h](fig8.png) ![i](fig9.png){#fig:subfig9}
 
+::: caption
 Figure 1: Caption. a --- 1, b --- 2, c --- 3, d --- 4, e --- 5, f --- 6,
 g --- 7, h --- 8, i --- 9
 :::
+:::
 
-::: {#fig:subfigures2 .subfigures}
-![a](fig1.png){#fig:subfig21}
+::: {#fig:subfigures2 .figure .subfigures}
+::: {#fig:subfig21 .figure}
+![1](fig1.png)
 
-![b](fig2.png){#fig:subfig22}
+::: caption
+a
+:::
+:::
 
-![c](fig3.png)
+::: {#fig:subfig22 .figure}
+![2](fig2.png)
 
-![d](fig4.png){#fig:subfig24}
+::: caption
+b
+:::
+:::
 
-![e](fig5.png)
+::: figure
+![3](fig3.png)
 
-![f](fig6.png){#fig:subfig26}
+::: caption
+c
+:::
+:::
 
-![g](fig7.png){#fig:subfig27}
+::: {#fig:subfig24 .figure}
+![4](fig4.png)
 
-![h](fig8.png)
+::: caption
+d
+:::
+:::
 
-![i](fig9.png){#fig:subfig29}
+::: figure
+![5](fig5.png)
 
+::: caption
+e
+:::
+:::
+
+::: {#fig:subfig26 .figure}
+![6](fig6.png)
+
+::: caption
+f
+:::
+:::
+
+::: {#fig:subfig27 .figure}
+![7](fig7.png)
+
+::: caption
+g
+:::
+:::
+
+::: figure
+![8](fig8.png)
+
+::: caption
+h
+:::
+:::
+
+::: {#fig:subfig29 .figure}
+![9](fig9.png)
+
+::: caption
+i
+:::
+:::
+
+::: caption
 Figure 2: Caption. a --- 1, b --- 2, c --- 3, d --- 4, e --- 5, f --- 6,
 g --- 7, h --- 8, i --- 9
+:::
 :::
 
 Figures themselves can be referenced fig. 2, as well as individual
diff --git a/test/m2m/titlesInRefs/expect.md b/test/m2m/titlesInRefs/expect.md
--- a/test/m2m/titlesInRefs/expect.md
+++ b/test/m2m/titlesInRefs/expect.md
@@ -1,6 +1,12 @@
 # Section {#sec:section}
 
-![Figure 1: A Figure](figure.png){#fig:figure}
+::: {#fig:figure .figure}
+![A Figure](figure.png)
+
+::: caption
+Figure 1: A Figure
+:::
+:::
 
 sec. 1 (Section)
 
diff --git a/test/test-integrative.hs b/test/test-integrative.hs
--- a/test/test-integrative.hs
+++ b/test/test-integrative.hs
@@ -41,7 +41,7 @@
     input <- runIO $ readFile ("test" </> "m2m" </> dir </> "input.md")
     expect_md <- runIO $ readFile ("test" </> "m2m" </> dir </> "expect.md")
     let ro = def { readerExtensions = pandocExtensions }
-        wo = def { writerExtensions = disableExtension Ext_raw_attribute pandocExtensions
+        wo = def { writerExtensions = disableExtension Ext_raw_html $ disableExtension Ext_raw_attribute pandocExtensions
                  , writerHighlightStyle=Just pygments
                  , writerListings = dir `elem` listingsDirs }
     p@(Pandoc meta _) <- runIO $ either (error . show) id <$> P.runIO (readMarkdown ro $ T.pack input)
diff --git a/test/test-pandoc-crossref.hs b/test/test-pandoc-crossref.hs
--- a/test/test-pandoc-crossref.hs
+++ b/test/test-pandoc-crossref.hs
@@ -21,19 +21,23 @@
 {-# LANGUAGE FlexibleContexts, CPP, OverloadedStrings, RankNTypes, ScopedTypeVariables #-}
 import Test.Hspec
 import Text.Pandoc hiding (getDataFileName)
-import Text.Pandoc.Builder
+import Text.Pandoc.Builder hiding (figure)
+import qualified Text.Pandoc.Builder as B
+import Control.Monad.Reader
 import Control.Monad.State
 import Data.List
 import Control.Arrow
 import qualified Data.Map as M
 import qualified Data.Text as T
 import qualified Data.Default as Df
+import Data.Maybe
 
 import Text.Pandoc.CrossRef
 import Text.Pandoc.CrossRef.Util.Options
 import Text.Pandoc.CrossRef.Util.Util
 import Text.Pandoc.CrossRef.References.Types
 import Lens.Micro
+import Text.Pandoc.CrossRef.References.Monad
 import qualified Text.Pandoc.CrossRef.References.Blocks as References.Blocks
 import qualified Text.Pandoc.CrossRef.References.Refs as References.Refs
 import qualified Text.Pandoc.CrossRef.References.List as References.List
@@ -85,32 +89,32 @@
 
     describe "References.Blocks.replaceBlocks" $ do
       it "Labels images" $
-        testAll (figure "test.jpg" "" "Test figure" "figure")
-        (figure "test.jpg" "" "Figure 1: Test figure" "figure",
+        testAll (figure "test.jpg" "" "Test figure" Nothing "figure")
+        (figure "test.jpg" "" "Figure 1: Test figure" (Just "Test figure") "figure",
           imgRefs =: M.fromList $ refRec' "fig:figure" 1 "Test figure")
       it "Labels subfigures" $
         testAll (
           divWith ("fig:subfigure",[],[]) (
-            para (figure' "fig:" "test1.jpg" "" "Test figure 1" "figure1")
-          <>para (figure' "fig:" "test2.jpg" "" "Test figure 2" "figure2")
+            para (figure' "test1.jpg" "" "Test figure 1" "figure1")
+          <>para (figure' "test2.jpg" "" "Test figure 2" "figure2")
           <>para (text "figure caption")
             ) <>
           divWith ("fig:subfigure2",[],[]) (
-            para (figure' "fig:" "test21.jpg" "" "Test figure 21" "figure21")
-          <>para (figure' "fig:" "test22.jpg" "" "Test figure 22" "figure22")
+            para (figure' "test21.jpg" "" "Test figure 21" "figure21")
+          <>para (figure' "test22.jpg" "" "Test figure 22" "figure22")
           <>para (text "figure caption 2")
             )
           )
         (
-          divWith ("fig:subfigure",["subfigures"],[]) (
-               para (figure' "fig:" "test1.jpg" "" "a" "figure1")
-            <> para (figure' "fig:" "test2.jpg" "" "b" "figure2")
-            <> para (text "Figure 1: figure caption. a — Test figure 1, b — Test figure 2")
+          figureWith ("fig:subfigure",["subfigures"],[])
+            (caption Nothing $ para (text "Figure 1: figure caption. a — Test figure 1, b — Test figure 2"))
+            ( para (figure' "test1.jpg" "" "a" "figure1")
+            <> para (figure' "test2.jpg" "" "b" "figure2")
             ) <>
-          divWith ("fig:subfigure2",["subfigures"],[]) (
-               para (figure' "fig:" "test21.jpg" "" "a" "figure21")
-            <> para (figure' "fig:" "test22.jpg" "" "b" "figure22")
-            <> para (text "Figure 2: figure caption 2. a — Test figure 21, b — Test figure 22")
+          figureWith ("fig:subfigure2",["subfigures"],[])
+            (caption Nothing $ para (text "Figure 2: figure caption 2. a — Test figure 21, b — Test figure 22"))
+            (  para (figure' "test21.jpg" "" "a" "figure21")
+            <> para (figure' "test22.jpg" "" "b" "figure22")
             )
         , imgRefs =: M.fromList [("fig:figure1",RefRec {
                                             refIndex = [(1,Nothing)],
@@ -302,7 +306,7 @@
             `test` "\\hypertarget{sec:section_label1}{%\n\\section{Section}\\label{sec:section_label1}}\n\nsec.~\\ref{sec:section_label1}"
 
         it "Image labels" $
-          figure "img.png" "" "Title" "figure_label1"
+          figure "img.png" "" "Title" Nothing "figure_label1"
             <> para (citeGen "fig:figure_label" [1])
             `test` "\\begin{figure}\n\\hypertarget{fig:figure_label1}{%\n\\centering\n\\includegraphics{img.png}\n\\caption{Title}\\label{fig:figure_label1}\n}\n\\end{figure}\n\nfig.~\\ref{fig:figure_label1}"
 
@@ -315,7 +319,19 @@
         it "Tbl labels" $
           table' "A table" "some_table1"
             <> para (citeGen "tbl:some_table" [1])
-            `test` "\\hypertarget{tbl:some_table1}{}\n\\begin{longtable}[]{@{}@{}}\n\\caption{\\label{tbl:some_table1}A table}\\tabularnewline\n\\toprule()\n\\endhead\n \\\\\n\\bottomrule()\n\\end{longtable}\n\ntbl.~\\ref{tbl:some_table1}"
+            `test` concat
+              [ "\\hypertarget{tbl:some_table1}{}\n"
+              , "\\begin{longtable}[]{@{}@{}}\n"
+              , "\\caption{\\label{tbl:some_table1}A table}\\tabularnewline\n"
+              , "\\toprule\\noalign{}\n"
+              , "\\endfirsthead\n"
+              , "\\endhead\n"
+              , "\\bottomrule\\noalign{}\n"
+              , "\\endlastfoot\n"
+              , " \\\\\n"
+              , "\\end{longtable}\n\n"
+              , "tbl.~\\ref{tbl:some_table1}"
+              ]
 #endif
 
         it "Code block labels" $ do
@@ -357,27 +373,34 @@
 testRefs'' p l1 l2 prop res = testRefs (para $ citeGen p l1) (set prop (refGen' p l1 l2) def) (para $ text res)
 
 testAll :: (Eq a, Data a, Show a) => Many a -> (Many a, References) -> Expectation
-testAll = testState f def
-  where f = References.Blocks.replaceAll defaultOptions
+testAll = testState References.Blocks.replaceAll def
 
-testState :: (Eq s, Eq a1, Show s, Show a1, Df.Default s) =>
-               ([a] -> State s [a1]) -> s -> Many a -> (Many a1, s) -> Expectation
-testState f init' arg res = runState (f $ toList arg) init' `shouldBe` first toList res
+testState :: (Show a1, Eq a1) => ([a2] -> WS [a1]) -> References -> Many a2 -> (Many a1, References) -> Expectation
+testState f init' arg res = runWSWithOptsInit defaultOptions init' (f $ toList arg) `shouldBe` first toList res
 
+runWSWithOptsInit :: Options -> References -> WS a -> (a, References)
+runWSWithOptsInit opts st = flip runState st . flip runReaderT opts . runWS
+
+runWSWithOpts :: Options -> WS a -> (a, References)
+runWSWithOpts opts = runWSWithOptsInit opts def
+
 testRefs :: Blocks -> References -> Blocks -> Expectation
-testRefs bs st rbs = testState (bottomUpM (References.Refs.replaceRefs defaultOptions)) st bs (rbs, st)
+testRefs bs st rbs = testState (bottomUpM References.Refs.replaceRefs) st bs (rbs, st)
 
 testCBCaptions :: Blocks -> Blocks -> Expectation
-testCBCaptions bs res = runState (bottomUpM (Util.CodeBlockCaptions.mkCodeBlockCaptions defaultOptions{Text.Pandoc.CrossRef.Util.Options.codeBlockCaptions=True}) (toList bs)) def `shouldBe` (toList res,def)
+testCBCaptions bs res = runWSWithOpts defaultOptions{Text.Pandoc.CrossRef.Util.Options.codeBlockCaptions=True}
+  (bottomUpM (Util.CodeBlockCaptions.mkCodeBlockCaptions) (toList bs)) `shouldBe` (toList res,def)
 
 testList :: Blocks -> References -> Blocks -> Expectation
-testList bs st res = runState (bottomUpM (References.List.listOf defaultOptions) (toList bs)) st `shouldBe` (toList res,st)
+testList bs st res = runWSWithOptsInit defaultOptions st (bottomUpM References.List.listOf (toList bs))
+   `shouldBe` (toList res,st)
 
-figure :: T.Text -> T.Text -> T.Text -> T.Text -> Blocks
-figure = (((para .) .) .) . figure' "fig:"
+figure :: T.Text -> T.Text -> T.Text -> Maybe T.Text -> T.Text -> Blocks
+figure src title cap malt ref = B.figureWith ("fig:" <> ref, [], [])
+  (caption Nothing $ para $ text cap) $ plain $ figure' src title (fromMaybe cap malt) ""
 
-figure' :: T.Text -> T.Text -> T.Text -> T.Text -> T.Text -> Inlines
-figure' p src title alt ref = imageWith ("fig:" <> ref, [], []) src (p <> title) (text alt)
+figure' :: T.Text -> T.Text -> T.Text -> T.Text -> Inlines
+figure' src title alt ref = imageWith (if T.null ref then mempty else "fig:" <> ref, [], []) src title (text alt)
 
 section :: T.Text -> Int -> T.Text -> Blocks
 section text' level label = headerWith ("sec:" <> label,[],[]) level (text text')
