diff --git a/crates/ui-egui/src/backstage.rs b/crates/ui-egui/src/backstage.rs
--- a/crates/ui-egui/src/backstage.rs
+++ b/crates/ui-egui/src/backstage.rs
@@ -112,6 +112,8 @@ pub struct Backstage {
     pub print_all: bool,
     /// Print: fit each sheet on one page.
     pub fit_to_page: bool,
+    /// Export and Save As: fit each sheet of a PDF on one page.
+    pub pdf_fit_to_page: bool,
     /// Print: the previewed page (0-based).
     preview_page: usize,
     /// Print: the preview for (document, revision, whole workbook, fit to page).
@@ -134,6 +136,7 @@ impl Backstage {
             props: Default::default(),
             print_all: false,
             fit_to_page: false,
+            pdf_fit_to_page: false,
             preview_page: 0,
             preview: None,
             save_format: "xlsx",
@@ -216,7 +219,7 @@ pub fn show(app: &mut SheetApp, ui: &mut Ui) {
                     Page::Info => info(app, ui, &mut bs),
                     Page::SaveAs => save_as(app, ui, &mut bs, &mut out),
                     Page::Print => print(app, ui, &mut bs, &mut out),
-                    Page::Export => export(app, ui, &mut out),
+                    Page::Export => export(app, ui, &mut bs, &mut out),
                     Page::Options => options(app, ui),
                     Page::Account => account(app, ui),
                 }
@@ -696,10 +699,14 @@ fn save_as(app: &mut SheetApp, ui: &mut Ui, bs: &mut Backstage, out: &mut Outcom
             if after != before || app.services.pick_save.is_none() {
                 out.close = true;
             }
-        } else if export_as(app, fmt) {
+        } else if export_as(app, fmt, bs.pdf_fit_to_page) {
             out.close = true;
         }
     }
+    if fmt == "pdf" {
+        ui.add_space(8.0);
+        ui.checkbox(&mut bs.pdf_fit_to_page, lang.tr("Fit Sheet on One Page"));
+    }
     ui.add_space(18.0);
     dim(ui, lang.tr("A CSV file, web page or PDF is a copy: the workbook keeps its own file."));
 }
@@ -870,28 +877,31 @@ fn paint_page(p: &egui::Painter, rect: Rect, paper_w: f32, page: &Json, wb: &gri
     }
 }
 
-fn export(app: &mut SheetApp, ui: &mut Ui, out: &mut Outcome) {
+fn export(app: &mut SheetApp, ui: &mut Ui, bs: &mut Backstage, out: &mut Outcome) {
     let lang = app.ui.language;
     if action_row(ui, Icon::Paper, lang.tr("Create PDF"), lang.tr("Save the sheet as a PDF document that keeps its page layout.")).clicked()
-        && export_as(app, "pdf")
+        && export_as(app, "pdf", bs.pdf_fit_to_page)
     {
         out.close = true;
     }
+    ui.add_space(6.0);
+    ui.checkbox(&mut bs.pdf_fit_to_page, lang.tr("Fit Sheet on One Page"));
     ui.add_space(14.0);
     section(ui, lang, "Change File Type");
     for (fmt, icon, title, detail) in [
         ("csv", Icon::TextColumns, "CSV (Comma delimited)", "Save the active sheet as comma-separated text."),
         ("html", Icon::Link, "Web Page (.html)", "Save the workbook as a web page."),
     ] {
-        if action_row(ui, icon, lang.tr(title), lang.tr(detail)).clicked() && export_as(app, fmt) {
+        if action_row(ui, icon, lang.tr(title), lang.tr(detail)).clicked() && export_as(app, fmt, false) {
             out.close = true;
         }
     }
 }
 
 /// Exports the active workbook as `pdf`, `csv` or `html`: through the save picker on the desktop,
-/// as a browser download on the web. Returns whether a file was written or handed over.
-pub fn export_as(app: &mut SheetApp, fmt: &str) -> bool {
+/// as a browser download on the web. `fit_to_page` fits each sheet of a PDF on one page; the other
+/// formats ignore it. Returns whether a file was written or handed over.
+pub fn export_as(app: &mut SheetApp, fmt: &str, fit_to_page: bool) -> bool {
     if !app.commit_edit(0, 0, false, false) {
         return false;
     }
@@ -907,7 +917,11 @@ pub fn export_as(app: &mut SheetApp, fmt: &str) -> bool {
         let Some(path) = pick(&format!("{stem}.{fmt}")) else { return false };
         // The picker may suggest a workbook extension; the export writes the chosen format.
         let path = std::path::Path::new(&path).with_extension(fmt).to_string_lossy().into_owned();
-        return match app.run(id, json!({"path": path})) {
+        let mut params = json!({"path": path});
+        if fmt == "pdf" && fit_to_page {
+            params["fitToPage"] = json!(true);
+        }
+        return match app.run(id, params) {
             Ok(_) => true,
             Err(e) => {
                 app.message = Some(("GridCraft".into(), crate::clean_error(&e)));
@@ -921,7 +935,8 @@ pub fn export_as(app: &mut SheetApp, fmt: &str) -> bool {
     }
     if fmt == "pdf" {
         // Without a path the PDF comes back as bytes, which `SheetApp::run` hands to the browser.
-        return match app.run(id, json!({})) {
+        let params = if fit_to_page { json!({"fitToPage": true}) } else { json!({}) };
+        return match app.run(id, params) {
             Ok(_) => true,
             Err(e) => {
                 app.message = Some(("GridCraft".into(), crate::clean_error(&e)));
