{"record":{"id":"04e436b4f0fe4671","repo":"parallax/jsPDF","slug":"couldn-t-assign-appearance-to-radiobutton-appeara","errorCode":null,"errorMessage":"Couldn't assign Appearance to RadioButton. Appearance was Invalid!","messagePattern":"Couldn't assign Appearance to RadioButton\\. Appearance was Invalid!","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/modules/acroform.js","lineNumber":2345,"sourceCode":"      }\n      _AS = \"/\" + pdfEscapeName(name);\n    }\n  });\n  this.caption = \"l\";\n  this.appearanceState = \"Off\";\n  // todo: set AppearanceType as variable that can be set from the\n  // outside...\n  this._AppearanceType = AcroFormAppearance.RadioButton.Circle;\n  // The Default appearanceType is the Circle\n  this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(\n    this.optionName\n  );\n};\ninherit(AcroFormChildClass, AcroFormField);\n\nAcroFormRadioButton.prototype.setAppearance = function(appearance) {\n  if (!(\"createAppearanceStream\" in appearance && \"getCA\" in appearance)) {\n    throw new Error(\n      \"Couldn't assign Appearance to RadioButton. Appearance was Invalid!\"\n    );\n  }\n  for (var objId in this.Kids) {\n    if (this.Kids.hasOwnProperty(objId)) {\n      var child = this.Kids[objId];\n      child.appearanceStreamContent = appearance.createAppearanceStream(\n        child.optionName\n      );\n      child.caption = appearance.getCA();\n    }\n  }\n};\n\nAcroFormRadioButton.prototype.createOption = function(name) {\n  // Create new Child for RadioGroup\n  var child = new AcroFormChildClass();\n  child.Parent = this;","sourceCodeStart":2327,"sourceCodeEnd":2363,"githubUrl":"https://github.com/parallax/jsPDF/blob/a3930ce03a585a26b2c76d12a0f413ce96f6d1a3/src/modules/acroform.js#L2327-L2363","documentation":"AcroFormRadioButton.setAppearance() accepts a custom appearance object to change how radio button options are rendered (e.g., Circle vs Cross style). The appearance object must implement two methods: createAppearanceStream(optionName) which returns the appearance dictionary, and getCA() which returns the caption character. This is a duck-typing check — the library does not use instanceof. The built-in valid appearances are AcroFormAppearance.RadioButton.Circle and AcroFormAppearance.RadioButton.Cross.","triggerScenarios":"Calling radioButton.setAppearance(someObject) where someObject lacks createAppearanceStream or getCA methods. Passing AcroFormAppearance.CheckBox (which has a different createAppearanceStream signature and no getCA). Passing a plain object literal or a partially constructed appearance.","commonSituations":"Developers trying to use a CheckBox appearance on a RadioButton, or constructing a custom appearance object without implementing both required methods. Copy-pasting appearance objects from examples that target different field types.","solutions":["Use a built-in appearance: radioButton.setAppearance(AcroFormAppearance.RadioButton.Cross) or AcroFormAppearance.RadioButton.Circle","If building a custom appearance, ensure it has both createAppearanceStream(name) and getCA() methods","Verify the appearance object with a type guard before calling setAppearance","Do not pass appearances designed for CheckBox or PushButton fields to a RadioButton"],"exampleFix":"// before\nradioButton.setAppearance({ custom: true }); // throws\nradioButton.setAppearance(AcroFormAppearance.CheckBox); // throws - no getCA\n\n// after\nradioButton.setAppearance(AcroFormAppearance.RadioButton.Cross);","handlingStrategy":"type-guard","validationCode":"// Check appearance object before calling setAppearance\nfunction isValidAppearance(obj) {\n  return obj !== null &&\n    typeof obj === 'object' &&\n    typeof obj.createAppearanceStream === 'function' &&\n    typeof obj.getCA === 'function';\n}\n\nif (isValidAppearance(myAppearance)) {\n  radioButton.setAppearance(myAppearance);\n}","typeGuard":"/**\n * @param {*} appearance\n * @returns {boolean}\n */\nfunction isRadioButtonAppearance(appearance) {\n  return typeof appearance === 'object' && appearance !== null &&\n    'createAppearanceStream' in appearance &&\n    'getCA' in appearance;\n}","tryCatchPattern":"try {\n  radioButton.setAppearance(customAppearance);\n} catch (e) {\n  // Fall back to built-in appearance\n  radioButton.setAppearance(jsPDF.AcroFormAppearance.RadioButton.Circle);\n}","preventionTips":["Only use AcroFormAppearance.RadioButton.Circle or .Cross for built-in appearances","If building custom appearances, implement both createAppearanceStream(name) and getCA()","Never pass CheckBox or PushButton appearances to a RadioButton"],"tags":["acroform","radio-button","appearance","duck-typing"],"backgroundTag":null,"analyzedSha":"a3930ce03a585a26b2c76d12a0f413ce96f6d1a3","analyzedAt":"2026-08-13T05:33:39.648Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}