Skip to content

04 — Forms (`PRINT-FORM`) — flagship

Status: NORMATIVE (internal print-safe guardrail + reference) Scope: PRINT-FORM-001 … PRINT-FORM-024 Related: Issue #2852 · 00 PRINT-LEGAL, 03 PRINT-LAYOUT, 06 PRINT-ALT, 08 PRINT-FIDELITY · converter: tools/docx2acroform

Why this section is the flagship. Our docx→AcroForm converter (tools/docx2acroform) turns a Word document into a fillable PDF by finding markers, redacting them, and dropping /Widget annotations in reading order (place.py). Every one of those widgets is a screen affordance. The moment a user hits Print, the AcroForm layer collapses to whatever ink sits on the page:

Digital affordanceFate on print
Tab order (/Annots sequence, /Tabs /S)Gone — reader fills in visual order
Auto-scaling / auto-size field textGone — fixed writing space only
Tooltip (/TU), field descriptionGone — never rendered to paper
Placeholder / default hintGone unless printed as static text
Format/validation scripts (AFDate_*, keystroke)Gone — no live validation
Required flag (field-flag bit 2)Gone — invisible metadata
Dropdown option list (/Opt)Gone — only the current value prints
Checkbox on/off appearancePrints as an empty box to mark by hand

A fillable AcroForm therefore becomes a hand-filled paper form the instant it is printed. This section governs the visual layer so the printed form is independently completable — and defines the geometry the converter must validate before it emits a widget it can never make print-safe after the fact.

Sourcing honesty. The handwriting-space and target-size numbers below are ergonomics / consensus practice, not codified law — there is no federal statute fixing “a name blank must be N points tall.” Where a number is a reasonable ergonomic floor with no traceable codified source, it is marked industry practice / unverified. Hard MUST rules appear only where they inherit from WCAG (1.4.1 color, 1.3.1/3.3.2 label association) or the effective-communication duty (00 PRINT-LEGAL). The 44×44 px touch-target norm (WCAG 2.5.5 / our project 44 px rule) is a touch standard; we borrow it as a hand-marking reference for checkbox/radio minimums and say so explicitly — it is an analogy, not a citation.

Unit convention. 1 in = 72 pt = 96 CSS px. Widget geometry in the converter is in PDF points. Where a rule states both, points are authoritative for our pipeline.


Physical writing space

Level: SHOULD Applies to: forms only Source: Handwriting ergonomics; clear-print form guidance (no codified federal minimum located) Source strength: industry practice (unverified for the exact number) Machine-checkable: yes Validation: Measure each text/date field widget rect height in points. Flag any fillable field whose printed writing height is below the floor. Recommended floor: ≥ 0.25 in (18 pt) of clear writing height; the current converter minimum is 14 pt (see implementation notes) — treat 14 pt as the hard reject floor and 18 pt as the target.

A hand-completed text field SHOULD provide at least 0.25 in (18 pt) of clear vertical writing space, and MUST NOT be emitted below 14 pt of writing height. Fields sized only to the source font’s cap height (i.e. no writing allowance) SHOULD be grown to the floor.

Rationale: Adult handwriting, and especially the larger, less-controlled hand of a writer with a tremor, motor, or low-vision disability, does not fit in a line-height-tall box. Too-short fields force writing to collide with the label above and the field below, making the entry unreadable — which then fails the recipient’s ability to process the form. Implementation notes: place.py sets _MIN_FIELD_HEIGHT = 14.0 with _HEIGHT_PAD = 2.0, and grows height to font_size_pt + 4 when a source font size is known. That 14 pt floor is a screen-legibility floor, not a hand-writing floor — it is below the 18 pt ergonomic target. Wired (issue #2858): the geometry gate now surfaces any field below the 18 pt target as a warning and rejects sub-14 pt fields (print_safe.check_text_field); underscore blanks keep the 14 pt growth floor. Reflow forms: give each blank ≥ 18 pt. Preserve mode: measure existing rule/underscore blanks; flag sub-floor ones.


Level: SHOULD Applies to: forms only Source: Handwriting ergonomics; clear-print form guidance Source strength: industry practice (unverified for the exact number) Machine-checkable: yes Validation: Measure each text field’s printed width against the expected content. Floor: ≥ 0.5 in (36 pt) for any hand-entry field; single-line name/address fields SHOULD be sized to the realistic content length (a name field of 36 pt is too short). Flag fields at or below the collapse floor.

A hand-completed field SHOULD be at least 0.5 in (36 pt) wide and SHOULD be sized to the realistic length of the expected entry; a name or address field SHOULD be substantially wider than the 36 pt floor. Fields SHOULD NOT be collapsed to the minimum merely because adjacent line content crowds them.

Rationale: A field too narrow for the expected content forces cramped or overflowing handwriting; the entry runs past the box and becomes illegible or is truncated by the reader. Width, unlike height, must track semantics (a ZIP needs less room than a street address). Implementation notes: place.py’s _field_rect expands a blank to field_width (default 144 pt), trims it back so it doesn’t overrun following words on the line, then clamps: x1 = max(x1, m.x0 + 36) — i.e. it “never collapses below half an inch.” Good: 36 pt is the hard floor. Gap: when line-crowding trims a name field down to ~36 pt, the field is technically legal but too short semantically. Surface trimmed-to-floor fields as a warning (PRINT-FORM-023). Tier-2 box/table-cell fields fill their detected rect exactly — inherit whatever the source drew.


Level: SHOULD Applies to: forms only Source: Motor-accessibility ergonomics; clear-print guidance Source strength: industry practice (unverified) Machine-checkable: partial Validation: Confirm the form’s default field height/width sits at the upper end of the ergonomic range for any form intended for a general or disability-affected audience (health, benefits, consent). Recommended: default to ≥ 22 pt height for such forms rather than the 18 pt minimum. Automatable as a stricter floor toggle; human confirms audience.

Forms likely to be completed by people with motor or vision disabilities (health intake, benefits, consent, accommodation-request forms) SHOULD default to generous writing space — a text-field height of ≥ 22 pt and correspondingly wider fields — rather than the bare minimum, because writing space cannot be enlarged after printing the way on-screen fields can auto-expand.

Rationale: A person with a tremor, arthritis, or low vision writes larger and less precisely; the AcroForm’s auto-scaling text that would have absorbed a long entry on screen does not exist on paper. Under-sizing the writing space excludes exactly the population the accessibility effort exists to serve. Implementation notes: Expose a converter profile (“generous / accessible forms”) that raises the height/width floors above the defaults. This is a policy knob, not a hard reject — but it should be the default for our own hosted forms service (see the Forms hosted-service plan). Reflow: parameterize the blank size token.


Level: SHOULD Applies to: forms only Source: Motor & cognitive accessibility consensus; plain-language form guidance Source strength: consensus standard Machine-checkable: yes (comb detection) Validation: Detect comb fields (AcroForm field-flag Comb, bit 25 of /Ff) and gridded one-character-per-box layouts (a run of equal, narrow adjacent cells). Flag all comb fields and per-character grids on hand-completed forms.

Character-cell “comb” fields, one-box-per-character grids, and gridded date boxes SHOULD NOT be used on hand-completed forms. Where fixed-width capture is genuinely required, the form SHOULD provide a single open field with a format hint before it (PRINT-FORM-013) instead of forced per-character cells.

Rationale: Comb boxes demand precise, evenly-spaced, cell-aligned printing that a writer with a tremor, dysgraphia, or low vision cannot produce; letters straddle cell walls and become unreadable. They optimize for machine capture at the direct expense of the human writer. The interactive comb also does not survive print as a usable affordance — it prints as a row of tiny boxes. Implementation notes: The converter does not currently generate comb fields (no Comb flag is ever set in place.py), which is correct — this rule keeps it that way. It becomes a refuse condition for any inbound spec (Tier-2 detection or confirm-mode JSON) that requests a comb field or is detected as a per-character grid: reject/flag rather than emit (see PRINT-FORM-024). Audit/preserve mode: flag existing comb fields in source PDFs.


Selectable targets — checkboxes & radios

Level: SHOULD Applies to: forms only Source: Ergonomics; borrowed from the 44×44 px touch-target norm (WCAG 2.5.5 / project 44 px rule) Source strength: consensus standard (touch-norm borrowed as hand-marking reference — analogy, not citation) Machine-checkable: yes Validation: Measure each checkbox widget’s printed side length. Floor: ≥ 0.19 in (14 pt / ~5 mm) per side is the recommended hand-marking minimum and ≥ 0.25 in (18 pt / ~6.5 mm) the target. The converter currently emits side = max(source_height, 10 pt); the geometry gate (PRINT-FORM-023/024) hard-rejects below 10 pt and warns in the 10–14 pt band — so 14 pt is the recommended floor, not an absolute reject threshold. Flag any checkbox below 14 pt.

A hand-markable checkbox SHOULD be at least 14 pt (~5 mm) per side and SHOULD default to 18 pt (~6.5 mm). Checkboxes SHOULD NOT be emitted at the source glyph height when that height is below the floor.

Rationale: The 44×44 px WCAG touch target is a finger minimum; a pen tip is finer, so a smaller box is defensible for marking — but a box below ~5 mm is hard to see for low vision and hard to hit for low dexterity, and an X drawn in it spills over the walls. We borrow the touch norm as the reasoning for a minimum while acknowledging the number is smaller because the interaction differs. Implementation notes: Wired (issue #2858): place.py now grows every checkbox to the 14 pt hand-marking floor via print_safe.grow_checkbox_side (was max(m.height, 10.0)), and the geometry gate flags any box still below 14 pt. A source checkbox glyph is often only ~10 pt tall; growing it is a print-safety improvement, not a fidelity loss.


Level: SHOULD Applies to: forms only Source: Ergonomics; borrowed from the 44×44 px touch-target norm (WCAG 2.5.5 / project 44 px rule) Source strength: consensus standard (touch-norm borrowed — analogy, not citation) Machine-checkable: yes Validation: Measure each radio widget diameter. Same floors as checkboxes: ≥ 14 pt diameter minimum, ≥ 18 pt recommended. Flag sub-floor radios.

Hand-markable radio buttons SHOULD be at least 14 pt in diameter and SHOULD default to 18 pt, matching the checkbox floor.

Rationale: Identical to PRINT-FORM-005 — a circle is if anything slightly harder to mark cleanly than a square, so the floor is the same, not looser. Radios also prints as an empty circle; the “selected” dot only appears if hand-marked. Implementation notes: The converter maps Word choice controls to checkboxes/comboboxes; native PDF radio groups are less common in this pipeline. Where radios are emitted or detected, apply the same 14/18 pt floor and the same refuse condition as checkboxes. Ensure radios in one group are visually and geometrically consistent.


Level: SHOULD Applies to: forms only Source: Ergonomics; borrowed from touch-target spacing norms Source strength: industry practice (unverified for the exact number) Machine-checkable: yes Validation: Measure edge-to-edge gap between adjacent checkbox/radio widgets (and between a control and the next control’s label). Floor: ≥ 8 pt (~3 mm) clear space between adjacent selectable targets; larger for dense option lists. Flag targets whose bounding boxes are closer than the floor.

Adjacent checkboxes or radio buttons SHOULD have at least 8 pt (~3 mm) of clear space between them, and each control SHOULD sit clearly closer to its own label than to any neighboring control (PRINT-FORM-008, 03 PRINT-LAYOUT-003).

Rationale: Tightly packed targets invite mis-marks — a shaky hand marks the wrong box, or a mark bleeds into two — with no undo on paper. Spacing also protects the label-to-control proximity that carries meaning. Implementation notes: The converter places widgets in reading order but does not currently enforce inter-widget spacing. For generated (reflow) forms, set a minimum option gap. For preserve/detection, flag option clusters whose widgets abut. This is assistable where the source geometry is fixed.


Level: MUST Applies to: forms only Source: WCAG 1.3.1 / 3.3.2 intent (label–control programmatic + visible association) Source strength: our-implementation rule Machine-checkable: partial Validation: For each checkbox/radio, confirm exactly one label is unambiguously the nearest text, on a consistent side (all labels right of the box, or all left — not mixed), and closer to its own control than to any neighbor. Human confirms the correct label pairs. Automatable: flag controls with no adjacent text within the label gap, or ambiguous equidistant labels.

Each checkbox/radio MUST have a visibly associated label positioned consistently (conventionally to the right of the control) and closer to its own control than to any adjacent option. The pairing MUST be unambiguous on paper without relying on tab order or /TU.

Rationale: On screen the label–widget association is programmatic; on paper it is only spatial. If a box sits equidistant between two labels, or labels alternate sides, a reader cannot tell which option a mark selects — a correctness failure, not a cosmetic one. WCAG 1.3.1/3.3.2 mandate this association on screen; because that programmatic link vanishes on paper, we hold the spatial equivalent as a MUST on our own print-safe output (not a claim that WCAG governs paper). Implementation notes: place.py’s _nearest_label associates the label as text on the same line left of the marker, within _LABEL_GAP_MAX = 200 pt — that becomes the /TU tooltip, which does not print. So the printed association depends entirely on the source layout. The converter must not move a control away from its visible label. For reflow forms, bind label and control adjacently and consistently. Flag any control whose nearest visible text is ambiguous.


Signature, date, and named blocks

Level: SHOULD Applies to: forms only Source: Form-design consensus; e-signature/wet-signature practice Source strength: consensus standard / industry practice Machine-checkable: yes Validation: Measure signature widget width and height. Floors: width ≥ 2 in (144 pt), height ≥ 0.33 in (24 pt); a printed signature rule (line) SHOULD sit under the writing space with a printed “Signature” label and, where relevant, “Date.” Flag sub-floor signature blocks.

A signature block SHOULD provide at least 2 in (144 pt) of writing width and ≥ 24 pt of height, with a visible signature rule and a printed label. It SHOULD NOT be crammed onto a short blank or a line shared with dense text.

Rationale: Signatures are larger and more variable than printed entries; a short signature line produces an overrunning or cramped signature that a recipient may reject. The height matters because signatures have ascenders/descenders and flourishes. Implementation notes: place.py already handles this well: signature fields get width = max(field_width, 144.0) clamped to the page margin, and _SIG_HEIGHT = 40.0 pt — both comfortably above the floors. Keep these. Ensure the printed rule and “Signature / Date” labels are present in the visible layer (the widget itself prints as an empty box; the guiding line/label must be real ink). Keep signature blocks out of the binding gutter (03 PRINT-LAYOUT-012).


Level: SHOULD Applies to: forms only Source: Form-design consensus; PRINT-FORM-004 (no combs) Source strength: consensus standard Machine-checkable: yes Validation: Confirm date fields are a single open field (not a MM / DD / YYYY comb grid) at least ≥ 0.9 in (65 pt) wide with a format hint printed before the field (PRINT-FORM-013). Flag date fields implemented as per-character grids (→ PRINT-FORM-004/024).

A date field SHOULD be a single open writing space of at least 65 pt width with the expected format shown as a printed hint before the field (e.g. “Date (MM/DD/YYYY): ____”), and MUST NOT be a per-character comb grid.

Rationale: Date combs are the most common hostile field on real forms; a single labeled blank with a leading format hint is both easier to hand-complete and unambiguous. Implementation notes: The converter maps Word date pickers to an AFDate-validated text field (AFDate_FormatEx / AFDate_KeystrokeEx scripts in place.py). Critically, that validation and the format string are invisible on print — the reader sees only an empty box. Therefore the format hint MUST also exist as printed static text before the field, not solely in the AFDate script or /TU. This is the PRINT-FORM-017 metadata-loss problem applied to dates.


Level: SHOULD Applies to: forms only Source: Consent-validity / conspicuousness practice (see PRINT-LEGAL-012); form-design consensus Source strength: consensus standard + legal (conspicuousness) Machine-checkable: partial Validation: Confirm the signature block is preceded by clear space and that any binding terms the signer attests to are set at/above the body point-size floor, not buried in sub-minimum fine print adjacent to the line. Human confirms the attestation is conspicuous. Automatable: flag text below the point-size floor within N points of a signature widget.

A signature line SHOULD be separated by clear space from surrounding text, and the terms the signature attests to SHOULD be legible (at or above the body point-size floor, 01 PRINT-TYPO-001) rather than set as dense fine print crammed against the line. Fine print below the size floor SHOULD NOT sit immediately adjacent to a signature.

Rationale: A signature obtained against unreadable, sub-minimum fine print is both an accessibility failure (the low-vision signer cannot read what they attest to) and a conspicuousness/consent-validity risk. This is where accessibility and legal defensibility converge. Implementation notes: Flag any run below the type floor within, e.g., 24 pt of a signature widget. Preserve mode: common in real consent forms — surface for human review. This ties to PRINT-LEGAL-012 (consumer-contract conspicuousness) rather than re-deriving it here.


Labels, hints, and required-field indication

Level: MUST Applies to: forms only Source: WCAG 1.3.1 / 3.3.2 intent (label association) Source strength: our-implementation rule Machine-checkable: partial Validation: Confirm each field’s visible label is adjacent (above or immediately left) and that no label is separated from its field by a column or page break. Automatable: flag a field whose associated label text sits on a different page or column, or beyond the label-gap threshold. Human confirms correctness where ambiguous.

Every field MUST have a visible printed label positioned consistently (above, or immediately to the left) and adjacent to its control; a label MUST NOT be separated from its field by a column boundary or a page break, and a label that wraps MUST keep its field on the same page/column.

Rationale: The programmatic label association (/TU, tag <Label>) does not print. On paper, a field whose label is at the bottom of page 1 while the field is at the top of page 2 is unlabeled for the reader. Consistent side placement (03 PRINT-LAYOUT-003 proximity) is the only association mechanism left. Implementation notes: place.py derives the label from text left of the marker on the same line and only uses it for /TU. The printed label is whatever the source already drew — the converter must not orphan a field from its visible label. Enforce label–field togetherness against page/column breaks (PRINT-FORM-019). Reflow: keep label+field in one non-breaking group.


Level: SHOULD Applies to: forms only Source: Plain-language form guidance; WCAG 3.3.2 intent Source strength: consensus standard Machine-checkable: partial Validation: Confirm any format/instruction text for a field is positioned before (above or left of) the field in reading order, not after it. Automatable where instruction text is identifiable; else human review.

Instructions, examples, and format hints for a field SHOULD appear before the field in reading order (above or to its left), never after it. A field requiring a specific format SHOULD show that format as printed text preceding the writing space.

Rationale: A hint placed after the field is read too late — the person has already written the entry in the wrong format and cannot erase ink cleanly. Screen users get the hint via /TU on focus; paper users only get what precedes the blank. Implementation notes: Directly connected to PRINT-FORM-010 (date format) and PRINT-FORM-017: any hint that currently lives only in /TU/placeholder must be surfaced as printed static text before the field for the print-safe profile.


Level: MUST Applies to: forms only Source: WCAG 1.4.1 (Use of Color); project 44 px/contrast rules Source strength: our-implementation rule Machine-checkable: yes Validation: Confirm required fields are indicated by a non-color cue (the word “required”, an asterisk with a legend, or “(optional)” on the inverse set) that survives grayscale. Automatable: detect required-field indication that relies solely on a colored label/marker with no text/shape equivalent → fail. Verify the cue survives B&W (02 PRINT-COLOR-003).

Required fields MUST be indicated by a means that does not rely on color alone — a printed word (“required”), a symbol paired with a printed legend, or explicit “(optional)” marking of the non-required set — and the indication MUST remain perceivable on a black-and-white print.

Rationale: The AcroForm required flag (field-flag bit 2) is invisible metadata that never prints. If “required” is shown only by red text, a B&W print (and any color-blind reader) loses it entirely — the reader omits mandatory fields and the form is rejected. WCAG 1.4.1 forbids color as the sole visual means on screen; since that guarantee is lost in print, we hold the print equivalent as a MUST on our own output (not a claim that WCAG governs paper). Implementation notes: place.py sets _FF_REQUIRED (field-flag bit 2) on required fields — print-invisible. The converter must emit a printed required indicator into the visible layer for every field it flags required, and a color-only required cue in the source is a refuse/flag condition (PRINT-FORM-024). _looks_required infers required from the word “required” or a trailing ""; a bare "" is insufficient alone (PRINT-FORM-015).


Level: SHOULD Applies to: forms only Source: Plain-language / form-design consensus; extends PRINT-FORM-014 Source strength: consensus standard Machine-checkable: partial Validation: On any multi-page form, confirm the meaning of ”*” (or any required symbol) is legible on the same page as the fields that use it — a one-time legend on page 1 does not carry to page 3. Recommend the explicit word or a per-page legend. Flag asterisk usage on pages lacking a legend.

On multi-page forms, a required-field asterisk or symbol SHOULD NOT rely on a single legend at the top of the form; the legend SHOULD repeat on every page that uses the symbol, or each required field SHOULD carry an explicit printed word (“required”).

Rationale: Paper pages get separated. A reader completing page 3 has no access to the ”* = required” legend printed on page 1; the asterisks become meaningless. This is the forms-specific case of the general “paper loses global context” problem. Implementation notes: Reflow/paged-media: repeat the required-legend in a footer on each page, or prefer explicit words. Preserve/audit: flag multi-page forms whose only required legend is on page 1.


Metadata that vanishes on print (ANALYTICAL)

Level: SHOULD Applies to: forms only Source: Analytical (affordance-fate analysis) Source strength: consensus standard (analytical) Machine-checkable: partial Validation: Enumerate every field carrying interactive validation and confirm each has an equivalent static, printed instruction. Automatable: list fields with format/validation/keystroke scripts and check for a corresponding printed hint.

Any interactive validation a field would enforce on screen — format enforcement, range/required checks, live error messages — SHOULD be restated as static printed instructional text on the form, because none of it fires on paper.

Rationale — enumerate what is lost and the required substitute:

Interactive validation (screen)Print fateRequired visual substitute
Format mask / AFDate_FormatEx date formatNot enforced; box is blankPrinted format hint before the field (“MM/DD/YYYY”) — PRINT-FORM-010/013
Keystroke filter (AFDate_KeystrokeEx, numeric-only)Not enforcedPrinted instruction (“numbers only”)
Required check + “This field is required” messageNo message ever showsPrinted “required” indicator — PRINT-FORM-014
Range/comparison validation (“must be ≥ 18”)Not checkedPrinted constraint text near the field
Inline error text on submitNever appearsPrinted guidance + a contact/where-to-ask line
Calculated/auto-filled field (AFSimple_Calculate)Not computedPrinted formula or “office use — leave blank”

Implementation notes: place.py emits AFDate format/keystroke scripts for date fields; these are the concrete case. The print-safe profile MUST pair every such script with printed static text. Calculated/auto-populated fields need an explicit printed note (either the formula or “for office use — do not complete”), because a blank calculated field on paper is invisible to the filler.


Level: SHOULD Applies to: forms only Source: Analytical (affordance-fate analysis) Source strength: consensus standard (analytical) Machine-checkable: yes Validation: For every widget, enumerate its non-printing metadata and confirm each meaning-bearing item has a printed equivalent. Automatable: dump /TU, placeholder/default hint, /Opt list, and description for each field; flag any that carry information not present in the visible layer.

Information conveyed only through a tooltip (/TU), placeholder, default-value hint, field description, or dropdown option list SHOULD be reproduced in printed text wherever it is meaning-bearing, because none of these render to paper.

Rationale — enumerate lost metadata and its substitute:

Non-printing field metadataWhat it carriedRequired printed substitute
/TU tooltip (the converter’s field_label)Often the only label (from _nearest_label)A real printed visible label — PRINT-FORM-012
Placeholder / ghost textFormat or example (“e.g. Jane Doe”)Printed example before the field — PRINT-FORM-013
Default value on a text fieldSuggested/prefilled contentPrint the value as visible text if it matters
Dropdown/combobox /Opt option listThe full set of allowed choicesPrint the choices as a visible list or checkboxes
Editable-combo free-text flag”you may type your own”Printed “or write your own: ____“
Field description / long helpExtended guidancePrinted instruction block

Implementation notes: This is the single most dangerous loss in our pipeline because place.py frequently sets /TU (field_label) as the nearest text label — meaning a field whose only label is the tooltip becomes completely unlabeled on paper. For the print-safe profile the converter MUST verify a visible printed label exists, not just /TU. Dropdowns are especially bad: on print only the current value shows, so the reader never sees the other options — a dropdown on a print-targeted form should be rendered as a printed checklist/option list instead.


Order, breaks, and duplex

Level: SHOULD Applies to: forms only Source: Form-design consensus; WCAG 2.4.3 (Focus Order) intent Source strength: consensus standard Machine-checkable: partial Validation: Confirm the visual top-to-bottom / left-to-right completion order matches the AcroForm tab order (/Annots sequence + /Tabs). Automatable: compare widget geometric order against annotation/tab order and flag divergence. Human confirms multi-column completion order.

The visual completion order of a printed form SHOULD match the intended logical order, and SHOULD NOT diverge from the AcroForm tab order in a way that would confuse a user who fills the digital and printed versions differently. Multi-column forms SHOULD make the completion path visually unambiguous (03 PRINT-LAYOUT-001).

Rationale: On screen, Tab walks fields in /Annots order regardless of geometry; on paper the reader fills in visual order. If the two disagree (e.g. a two-column form tabbed down-then-across but read across-then-down), the digital and paper experiences collect fields in different sequences — and the paper reader may skip or double-back. Implementation notes: place.py sorts widgets (page, y, x) — top-to-bottom, left-to-right — before insertion and sets /Tabs /S (structure order). Good: this makes tab order ≈ visual reading order for single-column forms. For multi-column source, confirm the sort matches the intended order, and pass author index (source .docx order) to the tagger for <Form> sequencing (already done). Flag forms where geometric order and author index disagree.


Level: SHOULD Applies to: forms only Source: Form-design consensus; extends PRINT-FORM-012 Source strength: consensus standard Machine-checkable: yes Validation: Confirm no page break falls between a question/label and its field, between a field group’s members, or between a control and its label. Automatable: detect a label whose associated widget is on a different page than the label, or a radio/checkbox group split across a page break.

A page break SHOULD NOT fall between a label and its field, within a set of options that form one question, or between related fields that must be read together. Question–answer pairs and option groups SHOULD be kept together on one page.

Rationale: A field stranded on the next page from its label (or half a radio group on each of two pages) is completed wrong or skipped. The tag-tree grouping that would keep them associated for a screen reader has no effect on the paper’s physical break. Implementation notes: Reflow/paged-media: apply break-inside: avoid to the label+field group and to option clusters. Preserve mode: source pagination is fixed — flag any split group for human review. Cross-check with PRINT-FORM-012 label association.


Level: SHOULD Applies to: forms only Source: Print-production + form-design consensus (see 05 PRINT-SUBSTRATE-004) Source strength: consensus standard / production Machine-checkable: partial Validation: For duplex forms, confirm reverse-side fields are announced on the front (“continued on back”), that a signature is not isolated on an unexpected back page, and that paper opacity controls show-through of field rules/ink (05 PRINT-SUBSTRATE-001). Automatable: detect fields present on even (back) pages of a duplex form and flag for a front-side pointer.

Duplex forms SHOULD announce on the front that fields continue on the back, SHOULD NOT isolate the signature or critical fields on a reverse side without a clear pointer, and SHOULD use paper opaque enough that field rules and entries do not show through and confuse the reader (05 PRINT-SUBSTRATE-001).

Rationale: Reverse-side fields are the most common cause of an incompletely-returned paper form; a low-vision reader who misses “continued on back” simply never fills the back. Show-through of ruled lines can make a reader mark the wrong side. Implementation notes: Our converter emits single-sided widget geometry; duplexing is a printing/production choice made downstream. The print-safe profile should either default the form to single-sided or, if duplex is intended, require a front-side “continued on back” line and keep the signature on the last-read side. Ties to 05 PRINT-SUBSTRATE-004 duplex rules.


Level: MAY Applies to: forms only Source: Form-design / production consensus Source strength: consensus standard Machine-checkable: no Validation: Human confirms any tear-off/return panel repeats the identifying info needed to process it standalone (name/ID), that the tear line does not cut through a field or the binding, and that the retained and returned portions each make sense alone.

A detachable return section or tear-off panel MAY be used; when it is, it SHOULD repeat the identifying information needed to process it on its own, its tear/fold line SHOULD NOT pass through any writing field or signature, and both the retained and returned portions SHOULD be independently intelligible.

Rationale: A return strip that omits the filer’s name, or whose tear line bisects the signature, is unprocessable — and the reader has already destroyed the document by tearing. There is no digital equivalent of a tear-off, so this is MAY (only applies when the design uses one). Implementation notes: Not something the converter generates today. Relevant to the hosted-forms service if it offers mail-back templates. Keep fields and tear lines clear of each other (03 PRINT-LAYOUT-012 margins logic applied to the tear line).


Effective-communication tie-in

Level: MUST Applies to: all documents (forms in particular) Source: ADA Title II/III + §504 + §1557 effective-communication regime — see 00 PRINT-LEGAL-001/002/006/008 and 06 PRINT-ALT-009 Source strength: regulation (duty) + consensus (placement/wording) Machine-checkable: partial Validation: Confirm the form carries a printed notice telling the reader how to request an accessible/alternate format at no charge, in legible type (≥ body point-size floor), in a findable location (near the top or in a consistent footer). Automatable: check for the presence of the notice string; human confirms adequacy and no-surcharge language.

A form that a person must be able to read to complete or act on MUST carry a printed notice stating that an accessible or alternate format is available on request and at no additional charge, with a contact method. The notice MUST be legible (at or above the body point-size floor) and placed where a reader will find it.

Rationale: The effective-communication duty (PRINT-LEGAL) is only realizable if the reader knows how to invoke it — a person who cannot read the standard print must be told, in a form they can find, how to get an accessible version without being charged (PRINT-LEGAL-004 no-surcharge). Cross-references 06 PRINT-ALT-009/010 for the required content and our default emit-string; do not re-derive the law here. Implementation notes: The hosted-forms service and the reflow pipeline should emit the default request-notice string from PRINT-ALT-010 into a consistent footer. Preserve mode: flag forms lacking any such notice. This is the print-layer expression of the same duty the digital products surface elsewhere.


Our-implementation rules — the docx→AcroForm converter

These two rules are codeable gates for tools/docx2acroform (place.py, confirm.py, and any inbound Tier-2/confirm-mode spec). They specify what field geometry the converter MUST validate before emitting a /Widget, and the exact refuse/flag conditions — because a widget that is wrong on paper cannot be fixed after it is drawn. Numbers here are the ergonomic floors asserted above, expressed as converter thresholds.

Level: SHOULD Applies to: forms only Source: our-implementation rule (grounded in PRINT-FORM-001/002/005/006/009) Source strength: industry practice (our-implementation rule) Machine-checkable: yes Validation: Before create_widgets calls page.add_widget, compute the final widget rect and check it against the print-safe floors below. Emit a per-field record {name, type, height_pt, width_pt, side_pt, warnings[]}. A field at or above all floors passes; a field below any warning floor is emitted with a warning; a field below a reject floor triggers PRINT-FORM-024.

Before emitting a widget, the converter SHOULD validate the final rect geometry against print-safe floors and record any field that falls below the recommended (warning) thresholds:

Field typeReject floor (→ 024)Warning floorRecommended
Text (hand entry)height < 14 pt or width < 36 ptheight < 18 pt · width < 72 ptheight 18–22 pt
Dateheight < 14 pt · width < 50 ptwidth < 65 ptwidth ≥ 65 pt, hint printed
Checkboxside < 10 ptside < 14 ptside 18 pt
Radiodia < 10 ptdia < 14 ptdia 18 pt
Signatureheight < 24 pt · width < 108 ptwidth < 144 pt≥ 144×40 pt
Any fieldrect intrudes into the 36 pt page marginwithin 8 pt of another widgetclear

Rationale: The converter currently enforces only _MIN_FIELD_HEIGHT = 14 pt, a x0+36 width floor, a max(height,10) checkbox side, and the outer _PAGE_MARGIN = 36. Those keep widgets legal but several sit below the hand-marking ergonomic floors (10 pt checkbox, 14 pt text height, 36 pt trimmed text width). Validating against the print-safe floors before emission is the only point at which the geometry can still be grown or the field flagged. Implementation notes: Add a validate_geometry(spec, rect) step in place.py._field_rect/create_widgets returning warnings appended to spec.notes and to a machine-readable report. Wire the same check into confirm.py (reviewed-geometry path trusts the JSON — validate it too). The report feeds the audit/ACR surface and the hosted-forms pre-publish review. Do NOT silently grow a Tier-2 box/table-cell field that fills a real detected rect — flag instead, since growing it would overlap neighboring cells.


Level: SHOULD Applies to: forms only Source: our-implementation rule (grounded in PRINT-FORM-004/014 + WCAG 1.4.1) Source strength: industry practice (our-implementation rule) Machine-checkable: yes Validation: For each inbound field spec (Tier-1 marker, Tier-2 detected, or confirm-mode JSON), evaluate the refuse conditions below. On a refuse condition the converter MUST NOT emit the widget as-specified — it either auto-corrects to the floor (when safe) and warns, or skips the widget and records a hard error; on a flag condition it emits but records a warning that surfaces to the reviewer.

The converter MUST enforce these conditions before emitting a widget:

ConditionActionReason
Comb field requested (Comb//Ff bit 25) or per-character grid detectedRefuse — drop the comb; emit a single open field + printed format hint, or flag for reviewPRINT-FORM-004 (hostile to hand completion)
Sub-minimum height (text < 14 pt, checkbox/radio < 10 pt)Refuse — grow to the floor and warn if the source rect is an underscore/blank; flag (do not grow) if it fills a detected box/table-cellPRINT-FORM-001/005/006
Sub-minimum width (text < 36 pt, signature < 108 pt)Refuse/grow for underscore blanks; flag for detected boxesPRINT-FORM-002/009
Color-only required indicator (field flagged required but the only visible required cue is color)Flag — required widget metadata is print-invisible; require a printed non-color indicatorPRINT-FORM-014 / WCAG 1.4.1
Required flag with no visible printed label (/TU-only label)Flag — field is unlabeled on paperPRINT-FORM-012/017
Rect intrudes into page margin / binding gutterRefuse — clamp to margin (already done for outer edge); flag if clamping collapses the field below its width floor03 PRINT-LAYOUT-012
Dropdown on a print-targeted formFlag — options don’t print; recommend a printed checklistPRINT-FORM-017

Rationale: These are the specific ways a widget becomes unusable the moment it prints — and each is detectable at emit time. Auto-correcting the safe cases (grow an underscore blank, clamp a margin overrun) and flagging the unsafe ones (a detected box that can’t grow without overlap, a color-only required cue) gives a form that is either print-safe or explicitly marked as needing human attention, never silently broken. Implementation notes: Implement as a gate in place.py.create_widgets (and confirm.py) that runs the PRINT-FORM-023 geometry check plus these categorical checks, mutating the spec (grow) or appending a hard warning to spec.notes and a machine-readable reject reason. The converter already never sets Comb, so the comb refuse is primarily an inbound-spec guard (confirm-mode JSON / Tier-2). Surface the report in the hosted-forms pre-publish edit step so an author sees “3 fields too small for hand completion, 1 required field marked by color only” before publishing.


Cross-references

  • Physical writing space ↔ margins/gutter: PRINT-FORM-001/002/009 ↔ 03 PRINT-LAYOUT-012.
  • Selectable-target minimums ↔ touch-target norm: PRINT-FORM-005/006/007 ↔ WCAG 2.5.5 / project 44 px rule (borrowed, not cited).
  • Color-only required ↔ use-of-color: PRINT-FORM-014 ↔ WCAG 1.4.1, 02 PRINT-COLOR-003/004.
  • Lost metadata ↔ fidelity table: PRINT-FORM-016/017 ↔ 08 PRINT-FIDELITY-001.
  • Order/breaks ↔ layout: PRINT-FORM-018/019 ↔ 03 PRINT-LAYOUT-001.
  • Alternate-format notice ↔ effective communication: PRINT-FORM-022 ↔ 00 PRINT-LEGAL-001/002/006/008, 06 PRINT-ALT-009/010.
  • Converter gates ↔ audit/hosted-forms review: PRINT-FORM-023/024 ↔ 09 PRINT-VALID-002/003.