Skip to content

Footer wp:anchor vertical offset is treated as body height during pagination #3256

Open

Description

@MohitTilwani15

What happened?

Bug: DOCX with anchored footer shape paginates as ~1985 pages instead of 43

Summary

SuperDoc appears to misinterpret a floating anchored object in a DOCX footer as document body height, causing pagination to explode from ~43 pages to ~1985 pages.

The same DOCX opens normally in Microsoft Word and reports 43 pages in the DOCX metadata.

Environment

  • Package: superdoc
  • Version: 1.32.0
  • Usage: CDN build
  • URL used: https://cdn.jsdelivr.net/npm/superdoc/dist/superdoc.min.js
  • Browser: Chrome / Chromium
  • Mode: paginated SuperDoc editor

Observed behavior

When loading the attached DOCX in SuperDoc, pagination reports around 1985 pages and the editor becomes unusable.

Expected behavior

The document should paginate to approximately 43 pages, matching Microsoft Word / DOCX metadata.

Minimal finding

The issue appears to be triggered by a floating anchored footer object in:

word/footer2.xml
Specifically this vertical anchor offset:

<wp:positionV relativeFrom="paragraph">
wp:posOffset10223818</wp:posOffset>
</wp:positionV>
This object is inside an mc:AlternateContent block in the footer and represents a footer confidentiality label / shape.

Microsoft Word handles this as a footer-positioned floating object. SuperDoc appears to include the large vertical offset in document layout/pagination height, causing the huge page count.

Reproduction
Load the attached DOCX with:

new SuperDoc({
  selector: "#editor",
  document: file,
  documentMode: "editing",
  role: "editor",
  comments: { visible: true },
  modules: {
    trackChanges: {
      enabled: true,
      mode: "review",
      replacements: "independent",
      visible: true,
    },
  },
});

Isolation results

I tested multiple DOCX variants to isolate the cause:

  • Removing embedded fonts: still broken
  • Removing custom XML: still broken
  • Removing comments: loads normally
  • Removing content controls: loads normally
  • Accepting tracked revisions: loads normally
  • Removing footnotes/endnotes: loads normally
  • Normalizing only word/footer2.xml: loads normally
  • Normalizing other header/footer files individually: still broken
  • Setting only the horizontal footer anchor offset to 0: still broken
  • Setting the vertical footer anchor offset to 0: fixed
  • Setting the vertical footer anchor offset to 720 or -720: fixed

The minimal fix was changing only the first active word/footer2.xml anchor vertical offset from:

<wp:posOffset>10223818</wp:posOffset>

to:

<wp:posOffset>0</wp:posOffset>

After that, SuperDoc reports 43 pages.

Expected handling
SuperDoc should not let a footer wp:anchor vertical offset inflate body pagination. Footer/header anchored objects should be constrained to the header/footer layout context, matching Word behavior.

Steps to reproduce

No response

SuperDoc version

No response

Browser

None

Additional context

No response

Activity

  1. linear commented on May 12, 2026

    @linear
  2. self-assigned this
    on May 14, 2026
  3. added
    status: assessedInitial assessment is complete; work is not necessarily prioritized.
    and removed
    status: investigatingThe report is being investigated or reproduced.
    on May 19, 2026
  4. vivienne-sd commented on May 19, 2026

    @vivienne-sd
    Collaborator

    Hi @MohitTilwani15 I was able to reproduce the pagination issue on a net new document, based on the info you shared. We're working on fixing it!

    You mentioned an attached .docx, but I didn't see it here. Do you mind sharing that? We'll confirm our fix against your specific document as well.

    I'll follow up here by next Tuesday (05/19) with an update on our work.

  5. added
    status: backlogIn the backlog; no delivery commitment.
    and removed
    status: assessedInitial assessment is complete; work is not necessarily prioritized.
    on May 19, 2026
  6. vivienne-sd commented on May 20, 2026

    @vivienne-sd
    Collaborator

    Hi @MohitTilwani15, we've got a broad er project for graphic handling set to kick off on 05/25 which will include the necessary work to address the pagination issue in this document. That works spans June, so I will keep you in the loop as we make progress there and update you as the exact issue you ran into is resolved. if you have the .docx you mentioned, please still feel free to send it: I'll test it against our fix as soon as it's in place.

  7. 1 remaining item

  8. added
    status: in-progressEngineering work, review, or testing is in progress.
    and removed
    status: assessedInitial assessment is complete; work is not necessarily prioritized.
    on Jun 22, 2026
  9. ohcedar commented on Jul 15, 2026

    @ohcedar

    We hit the same underlying issue in @harbour-enterprises/superdoc@1.44.1 with a different DOCX. In our case the default footer contained a floating wp:anchor with wrapSquare and a large paragraph-relative vertical wp:posOffset. Word rendered the document normally, but SuperDoc let that absolute footer position inflate the measured footer story height, consuming the body pagination area.

    The critical part of our downstream patch is in isHeaderFooterAbsoluteOverlay:

     function isHeaderFooterAbsoluteOverlay(block, kind, fragment, fragmentBottom, canvasHeight) {
       if (!kind) return false;
       if (block.anchor?.isAnchored !== true) return false;
    -  if (block.wrap?.type !== "None") return false;
       return fragment.y < 0 || fragmentBottom > canvasHeight;
     }

    The wrap.type !== "None" guard was the key problem. It meant an anchored header/footer object outside its story canvas was treated as contributing to header/footer story height whenever it used wrapSquare (or another wrapping mode), even though its position is an absolute overlay in that story.

    This remains narrowly scoped:

    • kind must identify a header/footer story;
    • the object must actually be anchored; and
    • the laid-out fragment must extend outside that story's canvas.

    Normal body objects and in-bounds wrapped header/footer objects are unchanged.

    Our isolation checks also supported this exact path: removing only the affected footer drawing fixed pagination; changing wrapSquare to wrapNone fixed it; and setting behindDoc="1" fixed it. With the patch, the original document rendered body content on all expected pages while retaining the footer object. We also verified the patch applies cleanly to a fresh 1.44.1 package and passes our full application test/build suite.

  10. added
    status: backlogIn the backlog; no delivery commitment.
    and removed
    status: in-progressEngineering work, review, or testing is in progress.
    on Aug 20, 2026
  11. caio-pizzol commented on Sep 11, 2026

    @caio-pizzol
    Contributor

    @MohitTilwani15 @ohcedar sorry for the long gap since our last update. We confirmed that the wrapped-footer case still affects V2: in our controlled example, the large footer offset increases the page count from 43 to 171. Removing wrapping or resetting the offset restores 43 pages. We’ve added these findings to the V2 engineering ticket. Your patch details were helpful, though we haven’t verified that patch as a V2 fix. We’ll keep this issue open and follow up when we have an update.

  12. added theissue type on Sep 11, 2026
  13. ghost added
    status: queuedEngineering work is queued; no delivery date is committed.
    on Oct 29, 2026
  14. ghost removed
    status: backlogIn the backlog; no delivery commitment.
    on Oct 29, 2026
  15. ohcedar commented on Oct 30, 2026

    @ohcedar

    Still reproduces in SuperDoc 2.28.0 (jsDelivr CDN build, Chrome), so this is still hitting us on real documents.

    A file-free repro: run this Python 3 script, then open each generated DOCX in SuperDoc. Both contain 60 body paragraphs and a footer image using wp:anchor, wrapSquare, and paragraph-relative vertical positioning. The only difference is wp:posOffset: 0 versus 8458835 EMU.

    import base64, zipfile
    R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
    W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
    PNG = base64.b64decode("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==")
    CT = """<?xml version="1.0" encoding="UTF-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Default Extension="png" ContentType="image/png"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/footer1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/></Types>"""
    def rels(*r): return '<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + "".join(f'<Relationship Id="{i}" Type="{R}/{t}" Target="{g}"/>' for i, t, g in r) + "</Relationships>"
    paras = "".join(f"<w:p><w:r><w:t>Clause {n}. The supplier will deliver the goods in good condition and the buyer will pay within thirty days of a valid invoice.</w:t></w:r></w:p>" for n in range(1, 61))
    DOC = f'<?xml version="1.0" encoding="UTF-8"?><w:document xmlns:w="{W}" xmlns:r="{R}"><w:body>{paras}<w:sectPr><w:footerReference w:type="default" r:id="rIdFtr"/><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/></w:sectPr></w:body></w:document>'
    def footer(off): return f'''<?xml version="1.0" encoding="UTF-8"?><w:ftr xmlns:w="{W}" xmlns:r="{R}" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><w:p><w:r><w:drawing><wp:anchor distT="0" distB="0" distL="114300" distR="114300" simplePos="0" relativeHeight="1" behindDoc="0" locked="0" layoutInCell="1" allowOverlap="1"><wp:simplePos x="0" y="0"/><wp:positionH relativeFrom="column"><wp:posOffset>0</wp:posOffset></wp:positionH><wp:positionV relativeFrom="paragraph"><wp:posOffset>{off}</wp:posOffset></wp:positionV><wp:extent cx="3437890" cy="438785"/><wp:effectExtent l="0" t="0" r="0" b="0"/><wp:wrapSquare wrapText="bothSides"/><wp:docPr id="1" name="logo"/><wp:cNvGraphicFramePr/><a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic><pic:nvPicPr><pic:cNvPr id="1" name="logo"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImg"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="3437890" cy="438785"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:anchor></w:drawing></w:r></w:p></w:ftr>'''
    for name, off in (("footer-offset-far.docx", 8458835), ("footer-offset-zero.docx", 0)):
        with zipfile.ZipFile(name, "w") as z:
            z.writestr("[Content_Types].xml", CT)
            z.writestr("_rels/.rels", rels(("rId1", "officeDocument", "word/document.xml")))
            z.writestr("word/document.xml", DOC)
            z.writestr("word/_rels/document.xml.rels", rels(("rIdFtr", "footer", "footer1.xml")))
            z.writestr("word/footer1.xml", footer(off))
            z.writestr("word/_rels/footer1.xml.rels", rels(("rIdImg", "image", "media/image1.png")))
            z.writestr("word/media/image1.png", PNG)

    Expected: the footer drawing's large vertical offset should not consume almost the entire body area. Word for Mac renders both files as four pages.

    Actual:

    File Word for Mac SuperDoc 2.28.0
    footer-offset-zero.docx 4 pages 3 pages
    footer-offset-far.docx 4 pages 120 pages

    The footer box grows from 48 px to 934 px on a 1056 px page, leaving one body line per page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

status: queuedEngineering work is queued; no delivery date is committed.

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions