A paragraph run carries a <w:footnoteReference> whose @w:id points at a footnote defined in word/footnotes.xml.
Library verdicts: python-docx: — docxjs: fail
| Feature id | docx/footnote |
|---|---|
| Format | docx |
| Category | references |
| Spec | ecma-376-5-part-1 § 17.11.10 w:footnoteReference |
| ID / part | Predicate | XPath | python-docx | docxjs |
|---|---|---|---|---|
footnote-reference-in-bodyword/document.xml | existAt least one <w:footnoteReference> with a @w:id must appear inside the document body. | //w:footnoteReference[@w:id] | — | — |
footnote-body-textword/footnotes.xml | existThe footnotes part must contain a user footnote whose body text is the fixture literal. | //w:footnote[not(@w:type) or (@w:type!='separator' and @w:type!='continuationSeparator')]/w:p/w:r/w:t[normalize-space()='This is the footnote text'] | — | — |
| ID | Predicate | Selector | python-docx | docxjs |
|---|---|---|---|---|
footnote-anchor-rendered | css_selector/ existSome marker for the footnote reference should exist in the rendered DOM. Renderers often drop footnotes entirely — this is a known gap to track. | .docx-wrapper [data-footnote], .docx-wrapper .footnote, .docx-wrapper sup.footnote-ref, .docx-wrapper sup a | — | fail |
scripts/gen_footnote.py
#!/usr/bin/env python3
"""Generate ``fixtures/docx/footnote.docx``.
A minimal document exercising the ``w:footnoteReference`` element and
its companion ``w:footnote`` in ``word/footnotes.xml``. One paragraph
with a footnote attached to its first run; the footnote body text is
``This is the footnote text``.
Uses the fork's ``Document.footnotes.add(run, text=...)`` API
(python-docx >= 2026.05.0). The fork's ``Footnotes.add()`` takes a
target ``Run`` and appends a ``<w:footnoteReference>`` inside it,
allocates a fresh footnote id, and adds a matching ``<w:footnote>`` to
the footnotes part with the supplied text as a run in its first
paragraph.
"""
from __future__ import annotations
from pathlib import Path
from docx import Document
_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "docx" / "footnote.docx"
def main() -> int:
doc = Document()
paragraph = doc.add_paragraph("Paragraph with a footnote")
anchor_run = paragraph.runs[0]
doc.footnotes.add(anchor_run, text="This is the footnote text")
_OUT.parent.mkdir(parents=True, exist_ok=True)
doc.save(_OUT, reproducible=True)
print(_OUT)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "docx/footnote",
"title": "Footnote reference",
"format": "docx",
"category": "references",
"summary": "A paragraph run carries a <w:footnoteReference> whose @w:id points at a footnote defined in word/footnotes.xml.",
"spec": {
"source": "ecma-376-5-part-1",
"clause": "17.11.10",
"element": "w:footnoteReference",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/WordprocessingML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/wml.xsd",
"notes": "A footnote is split across two parts: a <w:footnoteReference w:id='N'/> element living inside a run in the main story, and a matching <w:footnote w:id='N'> in word/footnotes.xml carrying the footnote body. Footnote IDs 0 and 1 are reserved (separator, continuation separator); user-authored footnotes start at 2."
},
"fixtures": {
"machine": "docx/footnote",
"office": "docx/footnote"
},
"generator": {
"python": "scripts/gen_footnote.py"
},
"assertions": [
{
"id": "footnote-reference-in-body",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:footnoteReference[@w:id]",
"must": "exist",
"description": "At least one <w:footnoteReference> with a @w:id must appear inside the document body."
},
{
"id": "footnote-body-text",
"part": "word/footnotes.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:footnote[not(@w:type) or (@w:type!='separator' and @w:type!='continuationSeparator')]/w:p/w:r/w:t[normalize-space()='This is the footnote text']",
"must": "exist",
"description": "The footnotes part must contain a user footnote whose body text is the fixture literal."
}
],
"render_assertions": [
{
"id": "footnote-anchor-rendered",
"kind": "css_selector",
"selector": ".docx-wrapper [data-footnote], .docx-wrapper .footnote, .docx-wrapper sup.footnote-ref, .docx-wrapper sup a",
"must": "exist",
"description": "Some marker for the footnote reference should exist in the rendered DOM. Renderers often drop footnotes entirely — this is a known gap to track."
}
]
}
