Skip to content

.landscape does not keep page size for Word (enforce "A4" in landscape whilst default doc is US Letter) #12917

Open

Description

@mcanouil

I don't think there an easy or even a fix for this at least not by simply injecting OpenXML code.

Using the landscape shortcode for Word document will also have another issue: the page/section dimension might me different to the portrait page/section because the dimension is hardcoded in the shortcode.

In OpenXML, a new section has to contains height, width, etc. and as far as I know don't inherits elements, thus since footer is not defined in the section, it's not there in the end.

For instance, here is what the community contributed landscapes shortcode does for Word:

  • -- Define the end of a portrait section for DOCX
    local end_portrait_section = ooxml '<w:p><w:pPr><w:sectPr></w:sectPr></w:pPr></w:p>'
    -- Define the end of a landscape section for DOCX
    local end_landscape_section = ooxml [[
    <w:p>
    <w:pPr>
    <w:sectPr>
    <w:pgSz w:h="11906" w:w="16838" w:orient="landscape" />
    </w:sectPr>
    </w:pPr>
    </w:p>
    ]]

Originally posted by @mcanouil in #12628

Activity

  1. changed the title [-]`.landscape` does not keep page size for Word[/-] [+]`.landscape` does not keep page size for Word (enforce "US letter" in landscape)[/+] on Jun 11, 2025
  2. cscheid commented on Jun 11, 2025

    @cscheid
    Member

    w:h="11906" w:w="16838" this, presumably, is the width and height. I don't know what units they're in, and I don't know what size we end up producing. But if we knew the latter (someone with Microsoft Word installed can tell us) then we can deduce the former, and from there we can create a configurable setting. It's not going to be automatic, but it will at least be fixable.

  3. cscheid commented on Jun 11, 2025

    @cscheid
    Member

    This is my life now:

    Image
  4. cscheid commented on Jun 11, 2025

    @cscheid
    Member

    Ok, the unit is 1/20th of a point, cf Section 17.6.13, page 585:

    Image
  5. cscheid commented on Jun 11, 2025

    @cscheid
    Member

    one inch is 72 points, so this entry is in 1/1440's of an inch.

  6. mcanouil commented on Jun 11, 2025

    @mcanouil
    CollaboratorAuthor

    Sorry, I had all those informations (I forgot to open this issue already and remembered today).
    The hardcoded values are for the US Letter format.

    The issue is not really the size, but the fact that the sections do not inherit from the document and are required to have width/height set.

    The main issue with that is you can't retrieve the width/height dynamically (at least I did not find a way to do that easily by injecting OpenXML), so you would need to extract that information from the reference document itself.

  7. mcanouil commented on Jun 11, 2025

    @mcanouil
    CollaboratorAuthor

    Actually, it's the other way around: the reference document is using US Letter format, but the landscape filter uses A4 for landscape.

  8. changed the title [-]`.landscape` does not keep page size for Word (enforce "US letter" in landscape)[/-] [+]`.landscape` does not keep page size for Word (enforce "A4" in landscape while default doc is US Letter)[/+] on Jun 11, 2025
  9. changed the title [-]`.landscape` does not keep page size for Word (enforce "A4" in landscape while default doc is US Letter)[/-] [+]`.landscape` does not keep page size for Word (enforce "A4" in landscape whilst default doc is US Letter)[/+] on Jun 11, 2025
  10. cderv commented on Jun 11, 2025

    @cderv
    Member

    But if we knew the latter (someone with Microsoft Word installed can tell us)

    I have microsoft word if you need me to look at something specific or do some tests

  11. mcanouil commented on Jun 11, 2025

    @mcanouil
    CollaboratorAuthor

    FYI:

    ---
    format: docx
    ---
    
    ## Portrait Page
    
    {{< lipsum 1 >}}
    
    ## Landscape Page
    
    :::: {.landscape}
    {{< lipsum 1 >}}
    :::
    quarto render index.qmd --to docx
    unzip -d my-document-content index.docx
    Archive:  index.docx
      inflating: my-document-content/[Content_Types].xml  
      inflating: my-document-content/_rels/.rels  
      inflating: my-document-content/word/document.xml  
      inflating: my-document-content/word/_rels/document.xml.rels  
      inflating: my-document-content/word/_rels/footnotes.xml.rels  
      inflating: my-document-content/word/numbering.xml  
      inflating: my-document-content/word/styles.xml  
      inflating: my-document-content/word/footnotes.xml  
      inflating: my-document-content/word/comments.xml  
      inflating: my-document-content/docProps/core.xml  
      inflating: my-document-content/docProps/app.xml  
      inflating: my-document-content/docProps/custom.xml  
      inflating: my-document-content/word/theme/theme1.xml  
      inflating: my-document-content/word/settings.xml  
      inflating: my-document-content/word/webSettings.xml  
      inflating: my-document-content/word/fontTable.xml  

    What you want in this case is: my-document-content/word/document.xml

  12. added this to the v1.8 milestone on Jun 11, 2025
  13. cscheid commented on Jun 11, 2025

    @cscheid
    Member

    The main issue with that is you can't retrieve the width/height dynamically (at least I did not find a way to do that easily by injecting OpenXML), so you would need to extract that information from the reference document itself.

    Sure, but we can (for example) read key-value attributes from the .landscape div and use those values if they're given.

  14. mcanouil commented on Jun 11, 2025

    @mcanouil
    CollaboratorAuthor

    The default values need and would need to be consistent with the default reference document as well.

  15. mcanouil commented on Jun 11, 2025

    @mcanouil
    CollaboratorAuthor

    FYI, the unit is called "twip" and as foudn by Carlos: 1 twip = 1/1440 inch

    US Letter dimension: 8.5 × 11 inches, or 12240 × 15840 twips

  16. mcanouil commented on Jun 11, 2025

    @mcanouil
    CollaboratorAuthor

    A draft about this:

    Since page() is used for Typst, I wonder if it should support width/height as well (using auto as default).
    If so, then the "landscape" div becomes more general as it could be used to change page layout for Word and Typst.
    For LaTeX, it starts to get pretty tricky to allow height/width as the packaged used does not allow this natively.

  17. modified the milestones: v1.8, v1.9 on Aug 21, 2025
  18. modified the milestones: v1.9, v1.10 on Feb 17, 2026
  19. modified the milestones: v1.10, v1.11 on Jul 30, 2026
  20. mcanouil commented on Oct 26, 2026

    @mcanouil
    CollaboratorAuthor

    I looked at this again on the current main, and the default page size can't be fixed in the filter alone.

    Pandoc's default reference.docx has no w:pgSz in its w:sectPr, so a Word document from Quarto carries no page size at all.
    Word then uses its own default, which follows the regional settings: US Letter in the US, A4 in most other places.
    A custom reference document can set a page size, but Pandoc copies it only to the last section of the document.
    The section break that .landscape adds before the div is an empty <w:sectPr>, so the pages before it still get Word's default.
    Only the landscape section has a fixed size, the A4 w:w="16838" w:h="11906".

    So no fixed value fits everyone.
    Switching to US Letter would fix the mismatch for US users and create it for A4 users.

    I think this is best handled in the documentation.
    The Word Templates page covers styles only, and could get a part on page setup in the reference document: page size, orientation and margins, and which sections they apply to.
    The "Landscape mode" section of Article Layout could then say that Word landscape sections are A4, and link to that part.
    Both places could show how to set the size with raw OpenXML instead of the .landscape class, here for US Letter:

    ```{=openxml}
    <w:p><w:pPr><w:sectPr></w:sectPr></w:pPr></w:p>
    ```
    
    This will appear in landscape mode.
    
    ```{=openxml}
    <w:p><w:pPr><w:sectPr><w:pgSz w:w="15840" w:h="12240" w:orient="landscape"/></w:sectPr></w:pPr></w:p>
    ```

    The values are in twentieths of a point, so one inch is 1440 and one centimetre is about 567.

    (I did try various things, especially when working on "Better Word", but it appears to not be possible to have a proper and simple fix in the context of Pandoc and how docx works.)

  21. aborruso commented on Oct 28, 2026

    @aborruso
    Contributor

    Beyond documenting it, would it make sense to have .landscape do this automatically for docx? It seems a very common case to me: a report in portrait with one wide table or diagram on a landscape page.

    I tested the manual version in a real document: copying w:pgSz, w:pgMar and the w:footerReference from the last w:sectPr of the reference document into both section breaks (with width and height swapped for the landscape one) keeps page size, margins and page numbers in every section.

    Since the reference-doc path is known before rendering, maybe Quarto could read that w:sectPr once and hand it to the landscape.lua filter, instead of the fixed A4 values and the empty portrait w:sectPr. The key-value attributes on the div suggested above could then override it when needed.

  22. mcanouil commented on Oct 28, 2026

    @mcanouil
    CollaboratorAuthor

    I don't think landscape.lua should read the reference document, though.
    In the default case there's nothing to read.
    Quarto doesn't ship a reference document and runs Pandoc with its own data directory, so Pandoc falls back to its built-in reference.docx.
    The final w:sectPr of that file has no w:pgSz, no w:pgMar and no footer reference, so most users would see no change.

    For those with a custom reference document, the filter would have to find where reference-doc came from (format options, project or extension), open the archive and pull w:sectPr out of document.xml with string matching, since Pandoc's Lua API has no XML parser.
    The r:id of w:footerReference also points to relationships in the output document.
    Copying it from the reference document works today because Pandoc keeps the same IDs, but nothing promises that.

    If Quarto ever does this automatically, I think the cleaner place is after Pandoc, on the output .docx (or to completely write .docx from scratch without Pandoc).
    Its final w:sectPr already holds the page size, margins and footer references of the reference document, with the right IDs.
    A post-processing step could copy them into the section breaks and swap width and height for the landscape one.

    Quarto 2 (quarto-dev/q2) is where I'd expect that step to eventually live.
    Its Word output still goes through Pandoc's docx writer at the moment, and it runs the Quarto 1 Lua filters, landscape.lua included, unchanged.
    For now Pandoc's file is the final output, with no step after it.
    But Quarto 2 already reads OOXML in Rust (zip archive and XML parser) to check its docx output in tests, so editing section properties there would be far simpler than in a Lua filter.

    Until then, I'd still go with the documentation note and the raw OpenXML example above.

  23. modified the milestones: v1.11, v1.12 on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docxIssues with the docx formatenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions