• 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

79.76
/src/api/form/PDFDropdown.ts
1
import PDFDocument from '../PDFDocument';
2
import PDFPage from '../PDFPage';
54✔
3
import PDFFont from '../PDFFont';
54✔
4
import PDFField, {
54✔
5
  FieldAppearanceOptions,
6
  assertFieldAppearanceOptions,
7
} from './PDFField';
8
import {
54✔
9
  AppearanceProviderFor,
10
  normalizeAppearance,
11
  defaultDropdownAppearanceProvider,
12
} from './appearances';
13
import { rgb } from '../colors';
54✔
14
import { degrees } from '../rotations';
54✔
15

16
import {
54✔
17
  PDFHexString,
18
  PDFRef,
19
  PDFString,
20
  PDFWidgetAnnotation,
21
  PDFAcroComboBox,
22
  AcroChoiceFlags,
23
} from '../../core';
24
import { assertIs, assertOrUndefined, assertPositive } from '../../utils';
54✔
25
import { isPDFInstance, PDFClasses } from '../objects';
54✔
26

27
/**
28
 * Represents a dropdown field of a [[PDFForm]].
29
 *
30
 * [[PDFDropdown]] fields are interactive text boxes that display a single
31
 * element (the currently selected value). The purpose of a dropdown is to
32
 * enable users to select a single option from a set of possible options. Users
33
 * can click on a dropdown to view the full list of options it provides.
34
 * Clicking on an option in the list will cause it to be selected and displayed
35
 * in the dropdown's text box. Some dropdowns allow users to enter text
36
 * directly into the box from their keyboard, rather than only being allowed to
37
 * choose an option from the list (see [[PDFDropdown.isEditable]]).
38
 */
39
export default class PDFDropdown extends PDFField {
54✔
40
  static className = () => PDFClasses.PDFDropdown;
54✔
41
  myClass(): PDFClasses {
42
    return PDFClasses.PDFDropdown;
8✔
43
  }
44
  /**
45
   * > **NOTE:** You probably don't want to call this method directly. Instead,
46
   * > consider using the [[PDFForm.getDropdown]] method, which will create an
47
   * > instance of [[PDFDropdown]] for you.
48
   *
49
   * Create an instance of [[PDFDropdown]] from an existing acroComboBox and ref
50
   *
51
   * @param acroComboBox The underlying `PDFAcroComboBox` for this dropdown.
52
   * @param ref The unique reference for this dropdown.
53
   * @param doc The document to which this dropdown will belong.
54
   */
55
  static of = (acroComboBox: PDFAcroComboBox, ref: PDFRef, doc: PDFDocument) =>
54✔
56
    new PDFDropdown(acroComboBox, ref, doc);
87✔
57

58
  /** The low-level PDFAcroComboBox wrapped by this dropdown. */
59
  readonly acroField: PDFAcroComboBox;
60

61
  private constructor(
62
    acroComboBox: PDFAcroComboBox,
63
    ref: PDFRef,
64
    doc: PDFDocument,
65
  ) {
66
    super(acroComboBox, ref, doc);
87✔
67

68
    assertIs(acroComboBox, 'acroComboBox', [
87✔
69
      [PDFAcroComboBox, 'PDFAcroComboBox'],
70
    ]);
71

72
    this.acroField = acroComboBox;
87✔
73
  }
74

75
  /**
76
   * Get the list of available options for this dropdown. These options will be
77
   * displayed to users who click on this dropdown in a PDF reader.
78
   * For example:
79
   * ```js
80
   * const dropdown = form.getDropdown('some.dropdown.field')
81
   * const options = dropdown.getOptions()
82
   * console.log('Dropdown options:', options)
83
   * ```
84
   * @returns The options for this dropdown.
85
   */
86
  getOptions(): string[] {
87
    const rawOptions = this.acroField.getOptions();
6✔
88

89
    const options = new Array<string>(rawOptions.length);
6✔
90
    for (let idx = 0, len = options.length; idx < len; idx++) {
6✔
91
      const { display, value } = rawOptions[idx];
24✔
92
      options[idx] = (display ?? value).decodeText();
24!
93
    }
94

95
    return options;
6✔
96
  }
97

98
  /**
99
   * Get the selected options for this dropdown. These are the values that were
100
   * selected by a human user via a PDF reader, or programatically via
101
   * software.
102
   * For example:
103
   * ```js
104
   * const dropdown = form.getDropdown('some.dropdown.field')
105
   * const selections = dropdown.getSelected()
106
   * console.log('Dropdown selections:', selections)
107
   * ```
108
   * > **NOTE:** Note that PDF readers only display one selected option when
109
   * > rendering dropdowns. However, the PDF specification does allow for
110
   * > multiple values to be selected in a dropdown. As such, the `pdf-lib`
111
   * > API supports this. However, in most cases the array returned by this
112
   * > method will contain only a single element (or no elements).
113
   * @returns The selected options in this dropdown.
114
   */
115
  getSelected(): string[] {
116
    const values = this.acroField.getValues();
14✔
117

118
    const selected = new Array<string>(values.length);
14✔
119
    for (let idx = 0, len = values.length; idx < len; idx++) {
14✔
120
      selected[idx] = values[idx].decodeText();
11✔
121
    }
122

123
    return selected;
14✔
124
  }
125

126
  /**
127
   * Set the list of options that are available for this dropdown. These are
128
   * the values that will be available for users to select when they view this
129
   * dropdown in a PDF reader. Note that preexisting options for this dropdown
130
   * will be removed. Only the values passed as `options` will be available to
131
   * select.
132
   * For example:
133
   * ```js
134
   * const dropdown = form.getDropdown('planets.dropdown')
135
   * dropdown.setOptions(['Earth', 'Mars', 'Pluto', 'Venus'])
136
   * ```
137
   * @param options The options that should be available in this dropdown.
138
   */
139
  setOptions(options: string[]) {
140
    assertIs(options, 'options', [Array]);
×
141

142
    const optionObjects = new Array<{ value: PDFHexString }>(options.length);
×
143
    for (let idx = 0, len = options.length; idx < len; idx++) {
×
144
      optionObjects[idx] = { value: PDFHexString.fromText(options[idx]) };
×
145
    }
146
    this.acroField.setOptions(optionObjects);
×
147
  }
148

149
  /**
150
   * Add to the list of options that are available for this dropdown. Users
151
   * will be able to select these values in a PDF reader. In addition to the
152
   * values passed as `options`, any preexisting options for this dropdown will
153
   * still be available for users to select.
154
   * For example:
155
   * ```js
156
   * const dropdown = form.getDropdown('rockets.dropdown')
157
   * dropdown.addOptions(['Saturn IV', 'Falcon Heavy'])
158
   * ```
159
   * @param options New options that should be available in this dropdown.
160
   */
161
  addOptions(options: string | string[]) {
162
    assertIs(options, 'options', ['string', Array]);
×
163

164
    const optionsArr = Array.isArray(options) ? options : [options];
×
165

166
    const existingOptions: {
167
      value: PDFString | PDFHexString;
168
      display?: PDFString | PDFHexString;
169
    }[] = this.acroField.getOptions();
×
170

171
    const newOptions = new Array<{ value: PDFHexString }>(optionsArr.length);
×
172
    for (let idx = 0, len = optionsArr.length; idx < len; idx++) {
×
173
      newOptions[idx] = { value: PDFHexString.fromText(optionsArr[idx]) };
×
174
    }
175

176
    this.acroField.setOptions(existingOptions.concat(newOptions));
×
177
  }
178

179
  /**
180
   * Select one or more values for this dropdown. This operation is analogous
181
   * to a human user opening the dropdown in a PDF reader and clicking on a
182
   * value to select it. This method will update the underlying state of the
183
   * dropdown to indicate which values have been selected. PDF libraries and
184
   * readers will be able to extract these values from the saved document and
185
   * determine which values were selected.
186
   *
187
   * For example:
188
   * ```js
189
   * const dropdown = form.getDropdown('best.superhero.dropdown')
190
   * dropdown.select('One Punch Man')
191
   * ```
192
   *
193
   * This method will mark this dropdown as dirty, causing its appearance
194
   * streams to be updated when either [[PDFDocument.save]] or
195
   * [[PDFForm.updateFieldAppearances]] is called. The updated streams will
196
   * display the selected option inside the widgets of this dropdown.
197
   *
198
   * **IMPORTANT:** The default font used to update appearance streams is
199
   * [[StandardFonts.Helvetica]]. Note that this is a WinAnsi font. This means
200
   * that encoding errors will be thrown if the selected option for this field
201
   * contains characters outside the WinAnsi character set (the latin alphabet).
202
   *
203
   * Embedding a custom font and passing it to
204
   * [[PDFForm.updateFieldAppearances]] or [[PDFDropdown.updateAppearances]]
205
   * allows you to generate appearance streams with characters outside the
206
   * latin alphabet (assuming the custom font supports them).
207
   *
208
   * Selecting an option that does not exist in this dropdown's option list
209
   * (see [[PDFDropdown.getOptions]]) will enable editing on this dropdown
210
   * (see [[PDFDropdown.enableEditing]]).
211
   *
212
   * > **NOTE:** PDF readers only display one selected option when rendering
213
   * > dropdowns. However, the PDF specification does allow for multiple values
214
   * > to be selected in a dropdown. As such, the `pdf-lib` API supports this.
215
   * > However, it is not recommended to select more than one value with this
216
   * > method, as only one will be visible. [[PDFOptionList]] fields are better
217
   * > suited for displaying multiple selected values.
218
   *
219
   * @param options The options to be selected.
220
   * @param merge Whether or not existing selections should be preserved.
221
   */
222
  select(options: string | string[], merge = false) {
3✔
223
    assertIs(options, 'options', ['string', Array]);
4✔
224
    assertIs(merge, 'merge', ['boolean']);
4✔
225

226
    const optionsArr = Array.isArray(options) ? options : [options];
4✔
227

228
    const validOptions = this.getOptions();
4✔
229
    const hasCustomOption = optionsArr.find(
4✔
230
      (option) => !validOptions.includes(option),
5✔
231
    );
232
    if (hasCustomOption) this.enableEditing();
4✔
233

234
    this.markAsDirty();
4✔
235

236
    if (optionsArr.length > 1 || (optionsArr.length === 1 && merge)) {
4✔
237
      this.enableMultiselect();
2✔
238
    }
239

240
    const values = new Array<PDFHexString>(optionsArr.length);
4✔
241
    for (let idx = 0, len = optionsArr.length; idx < len; idx++) {
4✔
242
      values[idx] = PDFHexString.fromText(optionsArr[idx]);
5✔
243
    }
244

245
    if (merge) {
4✔
246
      const existingValues = this.acroField.getValues();
1✔
247
      this.acroField.setValues(existingValues.concat(values));
1✔
248
    } else {
249
      this.acroField.setValues(values);
3✔
250
    }
251
  }
252

253
  /**
254
   * Clear all selected values for this dropdown. This operation is equivalent
255
   * to selecting an empty list. This method will update the underlying state
256
   * of the dropdown to indicate that no values have been selected.
257
   * For example:
258
   * ```js
259
   * const dropdown = form.getDropdown('some.dropdown.field')
260
   * dropdown.clear()
261
   * ```
262
   * This method will mark this text field as dirty. See [[PDFDropdown.select]]
263
   * for more details about what this means.
264
   */
265
  clear() {
266
    this.markAsDirty();
1✔
267
    this.acroField.setValues([]);
1✔
268
  }
269

270
  /**
271
   * Set the font size for this field. Larger font sizes will result in larger
272
   * text being displayed when PDF readers render this dropdown. Font sizes may
273
   * be integer or floating point numbers. Supplying a negative font size will
274
   * cause this method to throw an error.
275
   *
276
   * For example:
277
   * ```js
278
   * const dropdown = form.getDropdown('some.dropdown.field')
279
   * dropdown.setFontSize(4)
280
   * dropdown.setFontSize(15.7)
281
   * ```
282
   *
283
   * > This method depends upon the existence of a default appearance
284
   * > (`/DA`) string. If this field does not have a default appearance string,
285
   * > or that string does not contain a font size (via the `Tf` operator),
286
   * > then this method will throw an error.
287
   *
288
   * @param fontSize The font size to be used when rendering text in this field.
289
   */
290
  setFontSize(fontSize: number) {
291
    assertPositive(fontSize, 'fontSize');
×
292
    this.acroField.setFontSize(fontSize);
×
293
    this.markAsDirty();
×
294
  }
295

296
  /**
297
   * Returns `true` if users are allowed to edit the selected value of this
298
   * dropdown directly and are not constrained by the list of available
299
   * options. See [[PDFDropdown.enableEditing]] and
300
   * [[PDFDropdown.disableEditing]]. For example:
301
   * ```js
302
   * const dropdown = form.getDropdown('some.dropdown.field')
303
   * if (dropdown.isEditable()) console.log('Editing is enabled')
304
   * ```
305
   * @returns Whether or not this dropdown is editable.
306
   */
307
  isEditable(): boolean {
308
    return this.acroField.hasFlag(AcroChoiceFlags.Edit);
3✔
309
  }
310

311
  /**
312
   * Allow users to edit the selected value of this dropdown in PDF readers
313
   * with their keyboard. This means that the selected value of this dropdown
314
   * will not be constrained by the list of available options. However, if this
315
   * dropdown has any available options, users will still be allowed to select
316
   * from that list.
317
   * For example:
318
   * ```js
319
   * const dropdown = form.getDropdown('some.dropdown.field')
320
   * dropdown.enableEditing()
321
   * ```
322
   */
323
  enableEditing() {
324
    this.acroField.setFlagTo(AcroChoiceFlags.Edit, true);
1✔
325
  }
326

327
  /**
328
   * Do not allow users to edit the selected value of this dropdown in PDF
329
   * readers with their keyboard. This will constrain the selected value of
330
   * this dropdown to the list of available options. Users will only be able
331
   * to select an option from that list.
332
   * For example:
333
   * ```js
334
   * const dropdown = form.getDropdown('some.dropdown.field')
335
   * dropdown.disableEditing()
336
   * ```
337
   */
338
  disableEditing() {
339
    this.acroField.setFlagTo(AcroChoiceFlags.Edit, false);
×
340
  }
341

342
  /**
343
   * Returns `true` if the option list of this dropdown is always displayed
344
   * in alphabetical order, irrespective of the order in which the options
345
   * were added to the dropdown. See [[PDFDropdown.enableSorting]] and
346
   * [[PDFDropdown.disableSorting]]. For example:
347
   * ```js
348
   * const dropdown = form.getDropdown('some.dropdown.field')
349
   * if (dropdown.isSorted()) console.log('Sorting is enabled')
350
   * ```
351
   * @returns Whether or not this dropdown's options are sorted.
352
   */
353
  isSorted(): boolean {
354
    return this.acroField.hasFlag(AcroChoiceFlags.Sort);
1✔
355
  }
356

357
  /**
358
   * Always display the option list of this dropdown in alphabetical order,
359
   * irrespective of the order in which the options were added to this dropdown.
360
   * For example:
361
   * ```js
362
   * const dropdown = form.getDropdown('some.dropdown.field')
363
   * dropdown.enableSorting()
364
   * ```
365
   */
366
  enableSorting() {
367
    this.acroField.setFlagTo(AcroChoiceFlags.Sort, true);
×
368
  }
369

370
  /**
371
   * Do not always display the option list of this dropdown in alphabetical
372
   * order. Instead, display the options in whichever order they were added
373
   * to the list. For example:
374
   * ```js
375
   * const dropdown = form.getDropdown('some.dropdown.field')
376
   * dropdown.disableSorting()
377
   * ```
378
   */
379
  disableSorting() {
380
    this.acroField.setFlagTo(AcroChoiceFlags.Sort, false);
×
381
  }
382

383
  /**
384
   * Returns `true` if multiple options can be selected from this dropdown's
385
   * option list. See [[PDFDropdown.enableMultiselect]] and
386
   * [[PDFDropdown.disableMultiselect]]. For example:
387
   * ```js
388
   * const dropdown = form.getDropdown('some.dropdown.field')
389
   * if (dropdown.isMultiselect()) console.log('Multiselect is enabled')
390
   * ```
391
   * @returns Whether or not multiple options can be selected.
392
   */
393
  isMultiselect(): boolean {
394
    return this.acroField.hasFlag(AcroChoiceFlags.MultiSelect);
1✔
395
  }
396

397
  /**
398
   * Allow users to select more than one option from this dropdown's option
399
   * list. For example:
400
   * ```js
401
   * const dropdown = form.getDropdown('some.dropdown.field')
402
   * dropdown.enableMultiselect()
403
   * ```
404
   */
405
  enableMultiselect() {
406
    this.acroField.setFlagTo(AcroChoiceFlags.MultiSelect, true);
2✔
407
  }
408

409
  /**
410
   * Do not allow users to select more than one option from this dropdown's
411
   * option list. For example:
412
   * ```js
413
   * const dropdown = form.getDropdown('some.dropdown.field')
414
   * dropdown.disableMultiselect()
415
   * ```
416
   */
417
  disableMultiselect() {
418
    this.acroField.setFlagTo(AcroChoiceFlags.MultiSelect, false);
×
419
  }
420

421
  /**
422
   * Returns `true` if the selected option should be spell checked by PDF
423
   * readers. Spell checking will only be performed if this dropdown allows
424
   * editing (see [[PDFDropdown.isEditable]]). See
425
   * [[PDFDropdown.enableSpellChecking]] and
426
   * [[PDFDropdown.disableSpellChecking]]. For example:
427
   * ```js
428
   * const dropdown = form.getDropdown('some.dropdown.field')
429
   * if (dropdown.isSpellChecked()) console.log('Spell checking is enabled')
430
   * ```
431
   * @returns Whether or not this dropdown can be spell checked.
432
   */
433
  isSpellChecked(): boolean {
434
    return !this.acroField.hasFlag(AcroChoiceFlags.DoNotSpellCheck);
1✔
435
  }
436

437
  /**
438
   * Allow PDF readers to spell check the selected option of this dropdown.
439
   * For example:
440
   * ```js
441
   * const dropdown = form.getDropdown('some.dropdown.field')
442
   * dropdown.enableSpellChecking()
443
   * ```
444
   */
445
  enableSpellChecking() {
446
    this.acroField.setFlagTo(AcroChoiceFlags.DoNotSpellCheck, false);
×
447
  }
448

449
  /**
450
   * Do not allow PDF readers to spell check the selected option of this
451
   * dropdown. For example:
452
   * ```js
453
   * const dropdown = form.getDropdown('some.dropdown.field')
454
   * dropdown.disableSpellChecking()
455
   * ```
456
   */
457
  disableSpellChecking() {
458
    this.acroField.setFlagTo(AcroChoiceFlags.DoNotSpellCheck, true);
×
459
  }
460

461
  /**
462
   * Returns `true` if the option selected by a user is stored, or "committed",
463
   * when the user clicks the option. The alternative is that the user's
464
   * selection is stored when the user leaves this dropdown field (by clicking
465
   * outside of it - on another field, for example). See
466
   * [[PDFDropdown.enableSelectOnClick]] and
467
   * [[PDFDropdown.disableSelectOnClick]]. For example:
468
   * ```js
469
   * const dropdown = form.getDropdown('some.dropdown.field')
470
   * if (dropdown.isSelectOnClick()) console.log('Select on click is enabled')
471
   * ```
472
   * @returns Whether or not options are selected immediately after they are
473
   *          clicked.
474
   */
475
  isSelectOnClick(): boolean {
476
    return this.acroField.hasFlag(AcroChoiceFlags.CommitOnSelChange);
1✔
477
  }
478

479
  /**
480
   * Store the option selected by a user immediately after the user clicks the
481
   * option. Do not wait for the user to leave this dropdown field (by clicking
482
   * outside of it - on another field, for example). For example:
483
   * ```js
484
   * const dropdown = form.getDropdown('some.dropdown.field')
485
   * dropdown.enableSelectOnClick()
486
   * ```
487
   */
488
  enableSelectOnClick() {
489
    this.acroField.setFlagTo(AcroChoiceFlags.CommitOnSelChange, true);
×
490
  }
491

492
  /**
493
   * Wait to store the option selected by a user until they leave this dropdown
494
   * field (by clicking outside of it - on another field, for example).
495
   * For example:
496
   * ```js
497
   * const dropdown = form.getDropdown('some.dropdown.field')
498
   * dropdown.disableSelectOnClick()
499
   * ```
500
   */
501
  disableSelectOnClick() {
502
    this.acroField.setFlagTo(AcroChoiceFlags.CommitOnSelChange, false);
×
503
  }
504

505
  /**
506
   * Show this dropdown on the specified page. For example:
507
   * ```js
508
   * const ubuntuFont = await pdfDoc.embedFont(ubuntuFontBytes)
509
   * const page = pdfDoc.addPage()
510
   *
511
   * const form = pdfDoc.getForm()
512
   * const dropdown = form.createDropdown('best.gundam')
513
   * dropdown.setOptions(['Exia', 'Dynames'])
514
   * dropdown.select('Exia')
515
   *
516
   * dropdown.addToPage(page, {
517
   *   x: 50,
518
   *   y: 75,
519
   *   width: 200,
520
   *   height: 100,
521
   *   textColor: rgb(1, 0, 0),
522
   *   backgroundColor: rgb(0, 1, 0),
523
   *   borderColor: rgb(0, 0, 1),
524
   *   borderWidth: 2,
525
   *   rotate: degrees(90),
526
   *   font: ubuntuFont,
527
   * })
528
   * ```
529
   * This will create a new widget for this dropdown field.
530
   * @param page The page to which this dropdown widget should be added.
531
   * @param options The options to be used when adding this dropdown widget.
532
   */
533
  addToPage(page: PDFPage, options?: FieldAppearanceOptions) {
534
    assertIs(page, 'page', [[PDFPage, 'PDFPage']]);
3✔
535
    assertFieldAppearanceOptions(options);
3✔
536

537
    if (!options) options = {};
3✔
538

539
    if (!('textColor' in options)) options.textColor = rgb(0, 0, 0);
3✔
540
    if (!('backgroundColor' in options)) options.backgroundColor = rgb(1, 1, 1);
3✔
541
    if (!('borderColor' in options)) options.borderColor = rgb(0, 0, 0);
3✔
542
    if (!('borderWidth' in options)) options.borderWidth = 1;
3✔
543

544
    // Create a widget for this dropdown
545
    const widget = this.createWidget({
3✔
546
      x: options.x ?? 0,
9!
547
      y: options.y ?? 0,
9!
548
      width: options.width ?? 200,
9!
549
      height: options.height ?? 50,
9!
550
      textColor: options.textColor,
551
      backgroundColor: options.backgroundColor,
552
      borderColor: options.borderColor,
553
      borderWidth: options.borderWidth ?? 0,
9!
554
      rotate: options.rotate ?? degrees(0),
9!
555
      hidden: options.hidden,
556
      page: page.ref,
557
    });
558
    const widgetRef = this.doc.context.register(widget.dict);
3✔
559

560
    // Add widget to this field
561
    this.acroField.addWidget(widgetRef);
3✔
562

563
    // Set appearance streams for widget
564
    const font = options.font ?? this.doc.getForm().getDefaultFont();
3!
565
    this.updateWidgetAppearance(widget, font);
3✔
566

567
    // Add widget to the given page
568
    page.node.addAnnot(widgetRef);
3✔
569
  }
570

571
  /**
572
   * Returns `true` if this dropdown has been marked as dirty, or if any of
573
   * this dropdown's widgets do not have an appearance stream. For example:
574
   * ```js
575
   * const dropdown = form.getDropdown('some.dropdown.field')
576
   * if (dropdown.needsAppearancesUpdate()) console.log('Needs update')
577
   * ```
578
   * @returns Whether or not this dropdown needs an appearance update.
579
   */
580
  needsAppearancesUpdate(): boolean {
581
    if (this.isDirty()) return true;
5✔
582

583
    const widgets = this.acroField.getWidgets();
4✔
584
    for (let idx = 0, len = widgets.length; idx < len; idx++) {
4✔
585
      const widget = widgets[idx];
13✔
586
      const hasAppearances = isPDFInstance(
13✔
587
        widget.getAppearances()?.normal,
39✔
588
        PDFClasses.PDFStream,
589
      );
590
      if (!hasAppearances) return true;
13✔
591
    }
592

593
    return false;
3✔
594
  }
595

596
  /**
597
   * Update the appearance streams for each of this dropdown's widgets using
598
   * the default appearance provider for dropdowns. For example:
599
   * ```js
600
   * const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica)
601
   * const dropdown = form.getDropdown('some.dropdown.field')
602
   * dropdown.defaultUpdateAppearances(helvetica)
603
   * ```
604
   * @param font The font to be used for creating the appearance streams.
605
   */
606
  defaultUpdateAppearances(font: PDFFont) {
607
    assertIs(font, 'font', [[PDFFont, 'PDFFont']]);
2✔
608
    this.updateAppearances(font);
2✔
609
  }
610

611
  /**
612
   * Update the appearance streams for each of this dropdown's widgets using
613
   * the given appearance provider. If no `provider` is passed, the default
614
   * appearance provider for dropdowns will be used. For example:
615
   * ```js
616
   * const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica)
617
   * const dropdown = form.getDropdown('some.dropdown.field')
618
   * dropdown.updateAppearances(helvetica, (field, widget, font) => {
619
   *   ...
620
   *   return drawTextField(...)
621
   * })
622
   * ```
623
   * @param font The font to be used for creating the appearance streams.
624
   * @param provider Optionally, the appearance provider to be used for
625
   *                 generating the contents of the appearance streams.
626
   */
627
  updateAppearances(
628
    font: PDFFont,
629
    provider?: AppearanceProviderFor<PDFDropdown>,
630
  ) {
631
    assertIs(font, 'font', [[PDFFont, 'PDFFont']]);
2✔
632
    assertOrUndefined(provider, 'provider', [Function]);
2✔
633

634
    const widgets = this.acroField.getWidgets();
2✔
635
    for (let idx = 0, len = widgets.length; idx < len; idx++) {
2✔
636
      const widget = widgets[idx];
5✔
637
      this.updateWidgetAppearance(widget, font, provider);
5✔
638
    }
639
    this.markAsClean();
2✔
640
  }
641

642
  // getOption(index: number): string {}
643
  // getSelectedIndices(): number[] {}
644
  // removeOptions(option: string | string[]) {}
645
  // removeIndices(option: number[]) {}
646
  // deselect(options: string | string[]) {}
647
  // deselectIndices(optionIndices: number[]) {}
648

649
  private updateWidgetAppearance(
650
    widget: PDFWidgetAnnotation,
651
    font: PDFFont,
652
    provider?: AppearanceProviderFor<PDFDropdown>,
653
  ) {
654
    const apProvider = provider ?? defaultDropdownAppearanceProvider;
8!
655
    const appearances = normalizeAppearance(apProvider(this, widget, font));
8✔
656
    this.updateWidgetAppearanceWithFont(widget, font, appearances);
8✔
657
  }
658
}
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