diff --git a/crates/xfa/src/layout/measure.rs b/crates/xfa/src/layout/measure.rs
index 7751012b8b..0200059910 100644
--- a/crates/xfa/src/layout/measure.rs
+++ b/crates/xfa/src/layout/measure.rs
@@ -247,10 +247,12 @@ impl Layouter<'_> {
match self.caption_reserve(f, inner_w, ctx) {
Some((Placement::Top | Placement::Bottom, r)) => ui + r,
Some((placement, r)) => {
- // A check box's caption without a reserve is drawn in all the box leaves.
+ // A check box's caption without a reserve is drawn in all the box leaves; any
+ // other caption beside the widget is as wide as its reserve (XFA 3.3 p. 645), the
+ // width `draw_field` gives it.
let w = match auto_check_reserve(f, placement, inner_w, None) {
Some(auto) => auto,
- None => inner_w - r,
+ None => r.min(inner_w),
};
let cap = f.caption.as_ref().map(|c| {
let rich = match &c.value {
diff --git a/crates/xfa/src/tests.rs b/crates/xfa/src/tests.rs
index 43d6633c56..d7cfd1ca83 100644
--- a/crates/xfa/src/tests.rs
+++ b/crates/xfa/src/tests.rs
@@ -3030,6 +3030,20 @@ fn a_flowed_subform_is_as_tall_as_its_content_whatever_its_minimum_height() {
assert!((top("") - flowed - (216.0 - 14.4)).abs() < 0.01, "{} against {flowed}", top(""));
}
+#[test]
+fn a_caption_beside_a_check_box_wraps_in_its_reserve() {
+ // A 7.5in check box whose right-hand caption reserves 6.5in: two lines of text, not one or
+ // two words to a line in the 1in the box keeps. The field after it follows directly.
+ let words = "Applicant does not authorize the office to permit a participating office access to the application as filed. ".repeat(2);
+ let body = format!(
+ r#"
{words}
"#
+ );
+ let form = layout_xml(&one_area_form(r#"layout="tb""#, &body)).unwrap();
+ let w = widgets(&form.pages[0]);
+ let gap = w[1].rect.y - w[0].rect.y;
+ assert!(gap < 72.0, "the check box took {gap}pt");
+}
+
#[test]
fn the_form_packet_restores_a_caption_a_script_changed() {
let body = r#"