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/Widgetannotations 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 affordance Fate on print Tab order ( /Annotssequence,/Tabs /S)Gone — reader fills in visual order Auto-scaling / auto-size field text Gone — fixed writing space only Tooltip ( /TU), field descriptionGone — never rendered to paper Placeholder / default hint Gone 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 appearance Prints 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. HardMUSTrules 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
PRINT-FORM-001 — Fill-space minimum height for hand completion
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.
PRINT-FORM-002 — Fill-space minimum width for hand completion
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.
PRINT-FORM-003 — Extra allowance for tremor / low dexterity / large handwriting
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.
PRINT-FORM-004 — Comb / boxed character-cell / gridded date fields are hostile
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
PRINT-FORM-005 — Checkbox minimum physical dimensions
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.
PRINT-FORM-006 — Radio-button minimum dimensions
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.
PRINT-FORM-007 — Spacing between adjacent selectable targets
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.
PRINT-FORM-008 — Visual label-to-control relationship for check/radio
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
PRINT-FORM-009 — Signature block line length and clear space
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).
PRINT-FORM-010 — Date block sizing (non-comb)
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.
PRINT-FORM-011 — Signature line not adjacent to dense fine print
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
PRINT-FORM-012 — Label placement/proximity and wrap/column/page-break behavior
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.
PRINT-FORM-013 — Instructions and format hints appear BEFORE the field
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.
PRINT-FORM-014 — Required-field indication not reliant on color alone
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).
PRINT-FORM-015 — Required indication not asterisk-only or top-legend-only on multi-page forms
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)
PRINT-FORM-016 — Validation/error messages have no print analogue
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 fate | Required visual substitute |
|---|---|---|
Format mask / AFDate_FormatEx date format | Not enforced; box is blank | Printed format hint before the field (“MM/DD/YYYY”) — PRINT-FORM-010/013 |
Keystroke filter (AFDate_KeystrokeEx, numeric-only) | Not enforced | Printed instruction (“numbers only”) |
| Required check + “This field is required” message | No message ever shows | Printed “required” indicator — PRINT-FORM-014 |
| Range/comparison validation (“must be ≥ 18”) | Not checked | Printed constraint text near the field |
| Inline error text on submit | Never appears | Printed guidance + a contact/where-to-ask line |
Calculated/auto-filled field (AFSimple_Calculate) | Not computed | Printed 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.
PRINT-FORM-017 — Tooltips / placeholder / field descriptions don’t print
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 metadata | What it carried | Required 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 text | Format or example (“e.g. Jane Doe”) | Printed example before the field — PRINT-FORM-013 |
| Default value on a text field | Suggested/prefilled content | Print the value as visible text if it matters |
Dropdown/combobox /Opt option list | The full set of allowed choices | Print 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 help | Extended guidance | Printed 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
PRINT-FORM-018 — Reading/completion order vs AcroForm tab order divergence
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.
PRINT-FORM-019 — Page breaks inside a field group / question–answer pair
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.
PRINT-FORM-020 — Duplex hazards: reverse-side fields, show-through, back-of-page signatures
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.
PRINT-FORM-021 — Detachable / return sections, tear-off strips, mail-back panels
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
PRINT-FORM-022 — Alternate-format request notice ON the form
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.
PRINT-FORM-023 — docx→AcroForm: field-geometry validation before emitting a widget
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 type | Reject floor (→ 024) | Warning floor | Recommended |
|---|---|---|---|
| Text (hand entry) | height < 14 pt or width < 36 pt | height < 18 pt · width < 72 pt | height 18–22 pt |
| Date | height < 14 pt · width < 50 pt | width < 65 pt | width ≥ 65 pt, hint printed |
| Checkbox | side < 10 pt | side < 14 pt | side 18 pt |
| Radio | dia < 10 pt | dia < 14 pt | dia 18 pt |
| Signature | height < 24 pt · width < 108 pt | width < 144 pt | ≥ 144×40 pt |
| Any field | rect intrudes into the 36 pt page margin | within 8 pt of another widget | clear |
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.
PRINT-FORM-024 — docx→AcroForm: refuse/flag conditions
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:
| Condition | Action | Reason |
|---|---|---|
Comb field requested (Comb//Ff bit 25) or per-character grid detected | Refuse — drop the comb; emit a single open field + printed format hint, or flag for review | PRINT-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-cell | PRINT-FORM-001/005/006 |
| Sub-minimum width (text < 36 pt, signature < 108 pt) | Refuse/grow for underscore blanks; flag for detected boxes | PRINT-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 indicator | PRINT-FORM-014 / WCAG 1.4.1 |
Required flag with no visible printed label (/TU-only label) | Flag — field is unlabeled on paper | PRINT-FORM-012/017 |
| Rect intrudes into page margin / binding gutter | Refuse — clamp to margin (already done for outer edge); flag if clamping collapses the field below its width floor | 03 PRINT-LAYOUT-012 |
| Dropdown on a print-targeted form | Flag — options don’t print; recommend a printed checklist | PRINT-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.