• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

adnsistemas / pdf-lib / #18

24 Mar 2026 08:15PM UTC coverage: 74.286% (+0.3%) from 74.001%
#18

push

David N. Abdala
Documentation change

2569 of 3981 branches covered (64.53%)

Branch coverage included in aggregate %.

7372 of 9401 relevant lines covered (78.42%)

297170.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.5
/src/api/form/PDFTextField.ts
1
import PDFDocument from '../PDFDocument';
2
import PDFPage from '../PDFPage';
54✔
3
import PDFFont from '../PDFFont';
54✔
4
import PDFImage from '../PDFImage';
5
import PDFField, {
54✔
6
  FieldAppearanceOptions,
7
  assertFieldAppearanceOptions,
8
} from './PDFField';
9
import {
54✔
10
  AppearanceProviderFor,
11
  normalizeAppearance,
12
  defaultTextFieldAppearanceProvider,
13
} from './appearances';
14
import { rgb } from '../colors';
54✔
15
import { degrees } from '../rotations';
54✔
16
import {
54✔
17
  RichTextFieldReadError,
18
  ExceededMaxLengthError,
19
  InvalidMaxLengthError,
20
} from '../errors';
21
import { ImageAlignment } from '../image/alignment';
54✔
22
import { TextAlignment } from '../text/alignment';
54✔
23

24
import {
54✔
25
  PDFHexString,
26
  PDFRef,
27
  PDFAcroText,
28
  AcroTextFlags,
29
  PDFWidgetAnnotation,
30
} from '../../core';
31
import {
54✔
32
  assertIs,
33
  assertIsOneOf,
34
  assertOrUndefined,
35
  assertPositive,
36
  assertRangeOrUndefined,
37
} from '../../utils';
38
import { isPDFInstance, PDFClasses } from '../objects';
54✔
39

40
/**
41
 * Represents a text field of a [[PDFForm]].
42
 *
43
 * [[PDFTextField]] fields are boxes that display text entered by the user. The
44
 * purpose of a text field is to enable users to enter text or view text values
45
 * in the document prefilled by software. Users can click on a text field and
46
 * input text via their keyboard. Some text fields allow multiple lines of text
47
 * to be entered (see [[PDFTextField.isMultiline]]).
48
 */
49
export default class PDFTextField extends PDFField {
54✔
50
  static className = () => PDFClasses.PDFTextField;
54✔
51
  myClass(): PDFClasses {
52
    return PDFClasses.PDFTextField;
15✔
53
  }
54
  /**
55
   * > **NOTE:** You probably don't want to call this method directly. Instead,
56
   * > consider using the [[PDFForm.getTextField]] method, which will create an
57
   * > instance of [[PDFTextField]] for you.
58
   *
59
   * Create an instance of [[PDFTextField]] from an existing acroText and ref
60
   *
61
   * @param acroText The underlying `PDFAcroText` for this text field.
62
   * @param ref The unique reference for this text field.
63
   * @param doc The document to which this text field will belong.
64
   */
65
  static of = (acroText: PDFAcroText, ref: PDFRef, doc: PDFDocument) =>
54✔
66
    new PDFTextField(acroText, ref, doc);
340✔
67

68
  /** The low-level PDFAcroText wrapped by this text field. */
69
  readonly acroField: PDFAcroText;
70

71
  private constructor(acroText: PDFAcroText, ref: PDFRef, doc: PDFDocument) {
72
    super(acroText, ref, doc);
340✔
73

74
    assertIs(acroText, 'acroText', [[PDFAcroText, 'PDFAcroText']]);
340✔
75

76
    this.acroField = acroText;
340✔
77
  }
78

79
  /**
80
   * Get the text that this field contains. This text is visible to users who
81
   * view this field in a PDF reader.
82
   *
83
   * For example:
84
   * ```js
85
   * const textField = form.getTextField('some.text.field')
86
   * const text = textField.getText()
87
   * console.log('Text field contents:', text)
88
   * ```
89
   *
90
   * Note that if this text field contains no underlying value, `undefined`
91
   * will be returned. Text fields may also contain an underlying value that
92
   * is simply an empty string (`''`). This detail is largely irrelevant for
93
   * most applications. In general, you'll want to treat both cases the same
94
   * way and simply consider the text field to be empty. In either case, the
95
   * text field will appear empty to users when viewed in a PDF reader.
96
   *
97
   * An error will be thrown if this is a rich text field. `pdf-lib` does not
98
   * support reading rich text fields. Nor do most PDF readers and writers.
99
   * Rich text fields are based on XFA (XML Forms Architecture). Relatively few
100
   * PDFs use rich text fields or XFA. Unlike PDF itself, XFA is not an ISO
101
   * standard. XFA has been deprecated in PDF 2.0:
102
   * * https://en.wikipedia.org/wiki/XFA
103
   * * http://blog.pdfshareforms.com/pdf-2-0-release-bid-farewell-xfa-forms/
104
   *
105
   * @returns The text contained in this text field.
106
   */
107
  getText(): string | undefined {
108
    const value = this.acroField.getValue();
22✔
109
    if (!value && this.isRichFormatted()) {
22!
110
      throw new RichTextFieldReadError(this.getName());
×
111
    }
112
    return value?.decodeText();
22✔
113
  }
114

115
  /**
116
   * Set the text for this field. This operation is analogous to a human user
117
   * clicking on the text field in a PDF reader and typing in text via their
118
   * keyboard. This method will update the underlying state of the text field
119
   * to indicate what text has been set. PDF libraries and readers will be able
120
   * to extract these values from the saved document and determine what text
121
   * was set.
122
   *
123
   * For example:
124
   * ```js
125
   * const textField = form.getTextField('best.superhero.text.field')
126
   * textField.setText('One Punch Man')
127
   * ```
128
   *
129
   * This method will mark this text field as dirty, causing its appearance
130
   * streams to be updated when either [[PDFDocument.save]] or
131
   * [[PDFForm.updateFieldAppearances]] is called. The updated streams will
132
   * display the text this field contains inside the widgets of this text
133
   * field.
134
   *
135
   * **IMPORTANT:** The default font used to update appearance streams is
136
   * [[StandardFonts.Helvetica]]. Note that this is a WinAnsi font. This means
137
   * that encoding errors will be thrown if this field contains text outside
138
   * the WinAnsi character set (the latin alphabet).
139
   *
140
   * Embedding a custom font and passing it to
141
   * [[PDFForm.updateFieldAppearances]] or [[PDFTextField.updateAppearances]]
142
   * allows you to generate appearance streams with characters outside the
143
   * latin alphabet (assuming the custom font supports them).
144
   *
145
   * If this is a rich text field, it will be converted to a standard text
146
   * field in order to set the text. `pdf-lib` does not support writing rich
147
   * text strings. Nor do most PDF readers and writers. See
148
   * [[PDFTextField.getText]] for more information about rich text fields and
149
   * their deprecation in PDF 2.0.
150
   *
151
   * @param text The text this field should contain.
152
   */
153
  setText(text: string | undefined) {
154
    assertOrUndefined(text, 'text', ['string']);
7✔
155

156
    const maxLength = this.getMaxLength();
7✔
157
    if (maxLength !== undefined && text && text.length > maxLength) {
7✔
158
      throw new ExceededMaxLengthError(text.length, maxLength, this.getName());
1✔
159
    }
160

161
    this.markAsDirty();
6✔
162
    this.disableRichFormatting();
6✔
163

164
    if (text) {
6!
165
      this.acroField.setValue(PDFHexString.fromText(text));
6✔
166
    } else {
167
      this.acroField.removeValue();
×
168
    }
169
  }
170

171
  /**
172
   * Get the alignment for this text field. This value represents the
173
   * justification of the text when it is displayed to the user in PDF readers.
174
   * There are three possible alignments: left, center, and right. For example:
175
   * ```js
176
   * const textField = form.getTextField('some.text.field')
177
   * const alignment = textField.getAlignment()
178
   * if (alignment === TextAlignment.Left) console.log('Text is left justified')
179
   * if (alignment === TextAlignment.Center) console.log('Text is centered')
180
   * if (alignment === TextAlignment.Right) console.log('Text is right justified')
181
   * ```
182
   * @returns The alignment of this text field.
183
   */
184
  getAlignment(): TextAlignment {
185
    const quadding = this.acroField.getQuadding();
14✔
186

187
    // prettier-ignore
188
    return (
14✔
189
        quadding === 0 ? TextAlignment.Left
14!
190
      : quadding === 1 ? TextAlignment.Center
14✔
191
      : quadding === 2 ? TextAlignment.Right
10✔
192
      : TextAlignment.Left
193
    );
194
  }
195

196
  /**
197
   * Set the alignment for this text field. This will determine the
198
   * justification of the text when it is displayed to the user in PDF readers.
199
   * There are three possible alignments: left, center, and right. For example:
200
   * ```js
201
   * const textField = form.getTextField('some.text.field')
202
   *
203
   * // Text will be left justified when displayed
204
   * textField.setAlignment(TextAlignment.Left)
205
   *
206
   * // Text will be centered when displayed
207
   * textField.setAlignment(TextAlignment.Center)
208
   *
209
   * // Text will be right justified when displayed
210
   * textField.setAlignment(TextAlignment.Right)
211
   * ```
212
   * This method will mark this text field as dirty. See
213
   * [[PDFTextField.setText]] for more details about what this means.
214
   * @param alignment The alignment for this text field.
215
   */
216
  setAlignment(alignment: TextAlignment) {
217
    assertIsOneOf(alignment, 'alignment', TextAlignment);
×
218
    this.markAsDirty();
×
219
    this.acroField.setQuadding(alignment);
×
220
  }
221

222
  /**
223
   * Get the maximum length of this field. This value represents the maximum
224
   * number of characters that can be typed into this field by the user. If
225
   * this field does not have a maximum length, `undefined` is returned.
226
   * For example:
227
   * ```js
228
   * const textField = form.getTextField('some.text.field')
229
   * const maxLength = textField.getMaxLength()
230
   * if (maxLength === undefined) console.log('No max length')
231
   * else console.log(`Max length is ${maxLength}`)
232
   * ```
233
   * @returns The maximum number of characters allowed in this field, or
234
   *          `undefined` if no limit exists.
235
   */
236
  getMaxLength(): number | undefined {
237
    return this.acroField.getMaxLength();
7✔
238
  }
239

240
  /**
241
   * Set the maximum length of this field. This limits the number of characters
242
   * that can be typed into this field by the user. This also limits the length
243
   * of the string that can be passed to [[PDFTextField.setText]]. This limit
244
   * can be removed by passing `undefined` as `maxLength`. For example:
245
   * ```js
246
   * const textField = form.getTextField('some.text.field')
247
   *
248
   * // Allow between 0 and 5 characters to be entered
249
   * textField.setMaxLength(5)
250
   *
251
   * // Allow any number of characters to be entered
252
   * textField.setMaxLength(undefined)
253
   * ```
254
   * This method will mark this text field as dirty. See
255
   * [[PDFTextField.setText]] for more details about what this means.
256
   * @param maxLength The maximum number of characters allowed in this field, or
257
   *                  `undefined` to remove the limit.
258
   */
259
  setMaxLength(maxLength?: number) {
260
    assertRangeOrUndefined(maxLength, 'maxLength', 0, Number.MAX_SAFE_INTEGER);
5✔
261

262
    this.markAsDirty();
5✔
263

264
    if (maxLength === undefined) {
5✔
265
      this.acroField.removeMaxLength();
1✔
266
    } else {
267
      const text = this.getText();
4✔
268
      if (text && text.length > maxLength) {
4✔
269
        throw new InvalidMaxLengthError(text.length, maxLength, this.getName());
1✔
270
      }
271
      this.acroField.setMaxLength(maxLength);
3✔
272
    }
273
  }
274

275
  /**
276
   * Remove the maximum length for this text field. This allows any number of
277
   * characters to be typed into this field by the user. For example:
278
   * ```js
279
   * const textField = form.getTextField('some.text.field')
280
   * textField.removeMaxLength()
281
   * ```
282
   * Calling this method is equivalent to passing `undefined` to
283
   * [[PDFTextField.setMaxLength]].
284
   */
285
  removeMaxLength() {
286
    this.markAsDirty();
×
287
    this.acroField.removeMaxLength();
×
288
  }
289

290
  /**
291
   * Display an image inside the bounds of this text field's widgets. For example:
292
   * ```js
293
   * const pngImage = await pdfDoc.embedPng(...)
294
   * const textField = form.getTextField('some.text.field')
295
   * textField.setImage(pngImage)
296
   * ```
297
   * This will update the appearances streams for each of this text field's widgets.
298
   * @param image The image that should be displayed.
299
   */
300
  setImage(image: PDFImage) {
301
    const fieldAlignment = this.getAlignment();
×
302

303
    // prettier-ignore
304
    const alignment =
305
        fieldAlignment === TextAlignment.Center ? ImageAlignment.Center
×
306
      : fieldAlignment === TextAlignment.Right ? ImageAlignment.Right
×
307
      : ImageAlignment.Left;
308

309
    const widgets = this.acroField.getWidgets();
×
310
    for (let idx = 0, len = widgets.length; idx < len; idx++) {
×
311
      const widget = widgets[idx];
×
312
      const streamRef = this.createImageAppearanceStream(
×
313
        widget,
314
        image,
315
        alignment,
316
      );
317
      this.updateWidgetAppearances(widget, { normal: streamRef });
×
318
    }
319

320
    this.markAsClean();
×
321
  }
322

323
  /**
324
   * Set the font size for this field. Larger font sizes will result in larger
325
   * text being displayed when PDF readers render this text field. Font sizes
326
   * may be integer or floating point numbers. Supplying a negative font size
327
   * will cause this method to throw an error.
328
   *
329
   * For example:
330
   * ```js
331
   * const textField = form.getTextField('some.text.field')
332
   * textField.setFontSize(4)
333
   * textField.setFontSize(15.7)
334
   * ```
335
   *
336
   * > This method depends upon the existence of a default appearance
337
   * > (`/DA`) string. If this field does not have a default appearance string,
338
   * > or that string does not contain a font size (via the `Tf` operator),
339
   * > then this method will throw an error.
340
   *
341
   * @param fontSize The font size to be used when rendering text in this field.
342
   */
343
  setFontSize(fontSize: number) {
344
    assertPositive(fontSize, 'fontSize');
×
345
    this.acroField.setFontSize(fontSize);
×
346
    this.markAsDirty();
×
347
  }
348

349
  /**
350
   * Returns `true` if each line of text is shown on a new line when this
351
   * field is displayed in a PDF reader. The alternative is that all lines of
352
   * text are merged onto a single line when displayed. See
353
   * [[PDFTextField.enableMultiline]] and [[PDFTextField.disableMultiline]].
354
   * For example:
355
   * ```js
356
   * const textField = form.getTextField('some.text.field')
357
   * if (textField.isMultiline()) console.log('Multiline is enabled')
358
   * ```
359
   * @returns Whether or not this is a multiline text field.
360
   */
361
  isMultiline(): boolean {
362
    return this.acroField.hasFlag(AcroTextFlags.Multiline);
11✔
363
  }
364

365
  /**
366
   * Display each line of text on a new line when this field is displayed in a
367
   * PDF reader. For example:
368
   * ```js
369
   * const textField = form.getTextField('some.text.field')
370
   * textField.enableMultiline()
371
   * ```
372
   * This method will mark this text field as dirty. See
373
   * [[PDFTextField.setText]] for more details about what this means.
374
   */
375
  enableMultiline() {
376
    this.markAsDirty();
×
377
    this.acroField.setFlagTo(AcroTextFlags.Multiline, true);
×
378
  }
379

380
  /**
381
   * Display each line of text on the same line when this field is displayed
382
   * in a PDF reader. For example:
383
   * ```js
384
   * const textField = form.getTextField('some.text.field')
385
   * textField.disableMultiline()
386
   * ```
387
   * This method will mark this text field as dirty. See
388
   * [[PDFTextField.setText]] for more details about what this means.
389
   */
390
  disableMultiline() {
391
    this.markAsDirty();
×
392
    this.acroField.setFlagTo(AcroTextFlags.Multiline, false);
×
393
  }
394

395
  /**
396
   * Returns `true` if this is a password text field. This means that the field
397
   * is intended for storing a secure password. See
398
   * [[PDFTextField.enablePassword]] and [[PDFTextField.disablePassword]].
399
   * For example:
400
   * ```js
401
   * const textField = form.getTextField('some.text.field')
402
   * if (textField.isPassword()) console.log('Password is enabled')
403
   * ```
404
   * @returns Whether or not this is a password text field.
405
   */
406
  isPassword(): boolean {
407
    return this.acroField.hasFlag(AcroTextFlags.Password);
1✔
408
  }
409

410
  /**
411
   * Indicate that this text field is intended for storing a secure password.
412
   * For example:
413
   * ```js
414
   * const textField = form.getTextField('some.text.field')
415
   * textField.enablePassword()
416
   * ```
417
   * Values entered into password text fields should not be displayed on the
418
   * screen by PDF readers. Most PDF readers will display the value as
419
   * asterisks or bullets. PDF readers should never store values entered by the
420
   * user into password text fields. Similarly, applications should not
421
   * write data to a password text field.
422
   *
423
   * **Please note that this method does not cause entered values to be
424
   * encrypted or secured in any way! It simply sets a flag that PDF software
425
   * and readers can access to determine the _purpose_ of this field.**
426
   */
427
  enablePassword() {
428
    this.acroField.setFlagTo(AcroTextFlags.Password, true);
×
429
  }
430

431
  /**
432
   * Indicate that this text field is **not** intended for storing a secure
433
   * password. For example:
434
   * ```js
435
   * const textField = form.getTextField('some.text.field')
436
   * textField.disablePassword()
437
   * ```
438
   */
439
  disablePassword() {
440
    this.acroField.setFlagTo(AcroTextFlags.Password, false);
×
441
  }
442

443
  /**
444
   * Returns `true` if the contents of this text field represent a file path.
445
   * See [[PDFTextField.enableFileSelection]] and
446
   * [[PDFTextField.disableFileSelection]]. For example:
447
   * ```js
448
   * const textField = form.getTextField('some.text.field')
449
   * if (textField.isFileSelector()) console.log('Is a file selector')
450
   * ```
451
   * @returns Whether or not this field should contain file paths.
452
   */
453
  isFileSelector(): boolean {
454
    return this.acroField.hasFlag(AcroTextFlags.FileSelect);
1✔
455
  }
456

457
  /**
458
   * Indicate that this text field is intended to store a file path. The
459
   * contents of the file stored at that path should be submitted as the value
460
   * of the field. For example:
461
   * ```js
462
   * const textField = form.getTextField('some.text.field')
463
   * textField.enableFileSelection()
464
   * ```
465
   */
466
  enableFileSelection() {
467
    this.acroField.setFlagTo(AcroTextFlags.FileSelect, true);
×
468
  }
469

470
  /**
471
   * Indicate that this text field is **not** intended to store a file path.
472
   * For example:
473
   * ```js
474
   * const textField = form.getTextField('some.text.field')
475
   * textField.disableFileSelection()
476
   * ```
477
   */
478
  disableFileSelection() {
479
    this.acroField.setFlagTo(AcroTextFlags.FileSelect, false);
×
480
  }
481

482
  /**
483
   * Returns `true` if the text entered in this field should be spell checked
484
   * by PDF readers. See [[PDFTextField.enableSpellChecking]] and
485
   * [[PDFTextField.disableSpellChecking]]. For example:
486
   * ```js
487
   * const textField = form.getTextField('some.text.field')
488
   * if (textField.isSpellChecked()) console.log('Spell checking is enabled')
489
   * ```
490
   * @returns Whether or not this field should be spell checked.
491
   */
492
  isSpellChecked(): boolean {
493
    return !this.acroField.hasFlag(AcroTextFlags.DoNotSpellCheck);
1✔
494
  }
495

496
  /**
497
   * Allow PDF readers to spell check the text entered in this field.
498
   * For example:
499
   * ```js
500
   * const textField = form.getTextField('some.text.field')
501
   * textField.enableSpellChecking()
502
   * ```
503
   */
504
  enableSpellChecking() {
505
    this.acroField.setFlagTo(AcroTextFlags.DoNotSpellCheck, false);
×
506
  }
507

508
  /**
509
   * Do not allow PDF readers to spell check the text entered in this field.
510
   * For example:
511
   * ```js
512
   * const textField = form.getTextField('some.text.field')
513
   * textField.disableSpellChecking()
514
   * ```
515
   */
516
  disableSpellChecking() {
517
    this.acroField.setFlagTo(AcroTextFlags.DoNotSpellCheck, true);
×
518
  }
519

520
  /**
521
   * Returns `true` if PDF readers should allow the user to scroll the text
522
   * field when its contents do not fit within the field's view bounds. See
523
   * [[PDFTextField.enableScrolling]] and [[PDFTextField.disableScrolling]].
524
   * For example:
525
   * ```js
526
   * const textField = form.getTextField('some.text.field')
527
   * if (textField.isScrollable()) console.log('Scrolling is enabled')
528
   * ```
529
   * @returns Whether or not the field is scrollable in PDF readers.
530
   */
531
  isScrollable(): boolean {
532
    return !this.acroField.hasFlag(AcroTextFlags.DoNotScroll);
1✔
533
  }
534

535
  /**
536
   * Allow PDF readers to present a scroll bar to the user when the contents
537
   * of this text field do not fit within its view bounds. For example:
538
   * ```js
539
   * const textField = form.getTextField('some.text.field')
540
   * textField.enableScrolling()
541
   * ```
542
   * A horizontal scroll bar should be shown for singleline fields. A vertical
543
   * scroll bar should be shown for multiline fields.
544
   */
545
  enableScrolling() {
546
    this.acroField.setFlagTo(AcroTextFlags.DoNotScroll, false);
×
547
  }
548

549
  /**
550
   * Do not allow PDF readers to present a scroll bar to the user when the
551
   * contents of this text field do not fit within its view bounds. For example:
552
   * ```js
553
   * const textField = form.getTextField('some.text.field')
554
   * textField.disableScrolling()
555
   * ```
556
   */
557
  disableScrolling() {
558
    this.acroField.setFlagTo(AcroTextFlags.DoNotScroll, true);
×
559
  }
560

561
  /**
562
   * Returns `true` if this is a combed text field. This means that the field
563
   * is split into `n` equal size cells with one character in each (where `n`
564
   * is equal to the max length of the text field). The result is that all
565
   * characters in this field are displayed an equal distance apart from one
566
   * another. See [[PDFTextField.enableCombing]] and
567
   * [[PDFTextField.disableCombing]]. For example:
568
   * ```js
569
   * const textField = form.getTextField('some.text.field')
570
   * if (textField.isCombed()) console.log('Combing is enabled')
571
   * ```
572
   * Note that in order for a text field to be combed, the following must be
573
   * true (in addition to enabling combing):
574
   * * It must not be a multiline field (see [[PDFTextField.isMultiline]])
575
   * * It must not be a password field (see [[PDFTextField.isPassword]])
576
   * * It must not be a file selector field (see [[PDFTextField.isFileSelector]])
577
   * * It must have a max length defined (see [[PDFTextField.setMaxLength]])
578
   * @returns Whether or not this field is combed.
579
   */
580
  isCombed(): boolean {
581
    return (
21✔
582
      this.acroField.hasFlag(AcroTextFlags.Comb) &&
21!
583
      !this.isMultiline() &&
584
      !this.isPassword() &&
585
      !this.isFileSelector() &&
586
      this.getMaxLength() !== undefined
587
    );
588
  }
589

590
  /**
591
   * Split this field into `n` equal size cells with one character in each
592
   * (where `n` is equal to the max length of the text field). This will cause
593
   * all characters in the field to be displayed an equal distance apart from
594
   * one another. For example:
595
   * ```js
596
   * const textField = form.getTextField('some.text.field')
597
   * textField.enableCombing()
598
   * ```
599
   *
600
   * In addition to calling this method, text fields must have a max length
601
   * defined in order to be combed (see [[PDFTextField.setMaxLength]]).
602
   *
603
   * This method will also call the following three methods internally:
604
   * * [[PDFTextField.disableMultiline]]
605
   * * [[PDFTextField.disablePassword]]
606
   * * [[PDFTextField.disableFileSelection]]
607
   *
608
   * This method will mark this text field as dirty. See
609
   * [[PDFTextField.setText]] for more details about what this means.
610
   */
611
  enableCombing() {
612
    if (this.getMaxLength() === undefined) {
×
613
      const msg = 'PDFTextFields must have a max length in order to be combed';
×
614
      console.warn(msg);
×
615
    }
616

617
    this.markAsDirty();
×
618

619
    this.disableMultiline();
×
620
    this.disablePassword();
×
621
    this.disableFileSelection();
×
622

623
    this.acroField.setFlagTo(AcroTextFlags.Comb, true);
×
624
  }
625

626
  /**
627
   * Turn off combing for this text field. For example:
628
   * ```js
629
   * const textField = form.getTextField('some.text.field')
630
   * textField.disableCombing()
631
   * ```
632
   * See [[PDFTextField.isCombed]] and [[PDFTextField.enableCombing]] for more
633
   * information about what combing is.
634
   *
635
   * This method will mark this text field as dirty. See
636
   * [[PDFTextField.setText]] for more details about what this means.
637
   */
638
  disableCombing() {
639
    this.markAsDirty();
×
640
    this.acroField.setFlagTo(AcroTextFlags.Comb, false);
×
641
  }
642

643
  /**
644
   * Returns `true` if this text field contains rich text. See
645
   * [[PDFTextField.enableRichFormatting]] and
646
   * [[PDFTextField.disableRichFormatting]]. For example:
647
   * ```js
648
   * const textField = form.getTextField('some.text.field')
649
   * if (textField.isRichFormatted()) console.log('Rich formatting enabled')
650
   * ```
651
   * @returns Whether or not this field contains rich text.
652
   */
653
  isRichFormatted(): boolean {
654
    return this.acroField.hasFlag(AcroTextFlags.RichText);
8✔
655
  }
656

657
  /**
658
   * Indicate that this field contains XFA data - or rich text. For example:
659
   * ```js
660
   * const textField = form.getTextField('some.text.field')
661
   * textField.enableRichFormatting()
662
   * ```
663
   * Note that `pdf-lib` does not support reading or writing rich text fields.
664
   * Nor do most PDF readers and writers. Rich text fields are based on XFA
665
   * (XML Forms Architecture). Relatively few PDFs use rich text fields or XFA.
666
   * Unlike PDF itself, XFA is not an ISO standard. XFA has been deprecated in
667
   * PDF 2.0:
668
   * * https://en.wikipedia.org/wiki/XFA
669
   * * http://blog.pdfshareforms.com/pdf-2-0-release-bid-farewell-xfa-forms/
670
   */
671
  enableRichFormatting() {
672
    this.acroField.setFlagTo(AcroTextFlags.RichText, true);
×
673
  }
674

675
  /**
676
   * Indicate that this is a standard text field that does not XFA data (rich
677
   * text). For example:
678
   * ```js
679
   * const textField = form.getTextField('some.text.field')
680
   * textField.disableRichFormatting()
681
   * ```
682
   */
683
  disableRichFormatting() {
684
    this.acroField.setFlagTo(AcroTextFlags.RichText, false);
6✔
685
  }
686

687
  /**
688
   * Show this text field on the specified page. For example:
689
   * ```js
690
   * const ubuntuFont = await pdfDoc.embedFont(ubuntuFontBytes)
691
   * const page = pdfDoc.addPage()
692
   *
693
   * const form = pdfDoc.getForm()
694
   * const textField = form.createTextField('best.gundam')
695
   * textField.setText('Exia')
696
   *
697
   * textField.addToPage(page, {
698
   *   x: 50,
699
   *   y: 75,
700
   *   width: 200,
701
   *   height: 100,
702
   *   textColor: rgb(1, 0, 0),
703
   *   backgroundColor: rgb(0, 1, 0),
704
   *   borderColor: rgb(0, 0, 1),
705
   *   borderWidth: 2,
706
   *   rotate: degrees(90),
707
   *   font: ubuntuFont,
708
   * })
709
   * ```
710
   * This will create a new widget for this text field.
711
   * @param page The page to which this text field widget should be added.
712
   * @param options The options to be used when adding this text field widget.
713
   */
714
  addToPage(page: PDFPage, options?: FieldAppearanceOptions) {
715
    assertIs(page, 'page', [[PDFPage, 'PDFPage']]);
5✔
716
    assertFieldAppearanceOptions(options);
5✔
717

718
    if (!options) options = {};
5✔
719

720
    if (!('textColor' in options)) options.textColor = rgb(0, 0, 0);
5✔
721
    if (!('backgroundColor' in options)) options.backgroundColor = rgb(1, 1, 1);
5✔
722
    if (!('borderColor' in options)) options.borderColor = rgb(0, 0, 0);
5✔
723
    if (!('borderWidth' in options)) options.borderWidth = 1;
5✔
724

725
    // Create a widget for this text field
726
    const widget = this.createWidget({
5✔
727
      x: options.x ?? 0,
15!
728
      y: options.y ?? 0,
15!
729
      width: options.width ?? 200,
15!
730
      height: options.height ?? 50,
15!
731
      textColor: options.textColor,
732
      backgroundColor: options.backgroundColor,
733
      borderColor: options.borderColor,
734
      borderWidth: options.borderWidth ?? 0,
15!
735
      rotate: options.rotate ?? degrees(0),
15!
736
      hidden: options.hidden,
737
      page: page.ref,
738
    });
739
    const widgetRef = this.doc.context.register(widget.dict);
5✔
740

741
    // Add widget to this field
742
    this.acroField.addWidget(widgetRef);
5✔
743

744
    // Set appearance streams for widget
745
    const font = options.font ?? this.doc.getForm().getDefaultFont();
5!
746
    this.updateWidgetAppearance(widget, font);
5✔
747

748
    // Add widget to the given page
749
    page.node.addAnnot(widgetRef);
5✔
750
  }
751

752
  /**
753
   * Returns `true` if this text field has been marked as dirty, or if any of
754
   * this text field's widgets do not have an appearance stream. For example:
755
   * ```js
756
   * const textField = form.getTextField('some.text.field')
757
   * if (textField.needsAppearancesUpdate()) console.log('Needs update')
758
   * ```
759
   * @returns Whether or not this text field needs an appearance update.
760
   */
761
  needsAppearancesUpdate(): boolean {
762
    if (this.isDirty()) return true;
17✔
763

764
    const widgets = this.acroField.getWidgets();
13✔
765
    for (let idx = 0, len = widgets.length; idx < len; idx++) {
13✔
766
      const widget = widgets[idx];
13✔
767
      const hasAppearances = isPDFInstance(
13✔
768
        widget.getAppearances()?.normal,
39✔
769
        PDFClasses.PDFStream,
770
      );
771
      if (!hasAppearances) return true;
13✔
772
    }
773

774
    return false;
12✔
775
  }
776

777
  /**
778
   * Update the appearance streams for each of this text field's widgets using
779
   * the default appearance provider for text fields. For example:
780
   * ```js
781
   * const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica)
782
   * const textField = form.getTextField('some.text.field')
783
   * textField.defaultUpdateAppearances(helvetica)
784
   * ```
785
   * @param font The font to be used for creating the appearance streams.
786
   */
787
  defaultUpdateAppearances(font: PDFFont) {
788
    assertIs(font, 'font', [[PDFFont, 'PDFFont']]);
5✔
789
    this.updateAppearances(font);
5✔
790
  }
791

792
  /**
793
   * Update the appearance streams for each of this text field's widgets using
794
   * the given appearance provider. If no `provider` is passed, the default
795
   * appearance provider for text fields will be used. For example:
796
   * ```js
797
   * const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica)
798
   * const textField = form.getTextField('some.text.field')
799
   * textField.updateAppearances(helvetica, (field, widget, font) => {
800
   *   ...
801
   *   return drawTextField(...)
802
   * })
803
   * ```
804
   * @param font The font to be used for creating the appearance streams.
805
   * @param provider Optionally, the appearance provider to be used for
806
   *                 generating the contents of the appearance streams.
807
   */
808
  updateAppearances(
809
    font: PDFFont,
810
    provider?: AppearanceProviderFor<PDFTextField>,
811
  ) {
812
    assertIs(font, 'font', [[PDFFont, 'PDFFont']]);
5✔
813
    assertOrUndefined(provider, 'provider', [Function]);
5✔
814

815
    const widgets = this.acroField.getWidgets();
5✔
816
    for (let idx = 0, len = widgets.length; idx < len; idx++) {
5✔
817
      const widget = widgets[idx];
5✔
818
      this.updateWidgetAppearance(widget, font, provider);
5✔
819
    }
820
    this.markAsClean();
5✔
821
  }
822

823
  private updateWidgetAppearance(
824
    widget: PDFWidgetAnnotation,
825
    font: PDFFont,
826
    provider?: AppearanceProviderFor<PDFTextField>,
827
  ) {
828
    const apProvider = provider ?? defaultTextFieldAppearanceProvider;
10!
829
    const appearances = normalizeAppearance(apProvider(this, widget, font));
10✔
830
    this.updateWidgetAppearanceWithFont(widget, font, appearances);
10✔
831
  }
832
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc