{"record":{"id":"a7b2691dae663085","repo":"angular/components","slug":"setcontenteditablevalue-can-only-be-called-on-a-c-a7b269","errorCode":null,"errorMessage":"setContenteditableValue can only be called on a `contenteditable` element.","messagePattern":"setContenteditableValue can only be called on a `contenteditable` element\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cdk/testing/selenium-webdriver/selenium-web-driver-element.ts","lineNumber":163,"sourceCode":"    return this._executeScript(\n      (element: Element) => (element.textContent || '').trim(),\n      this.element(),\n    );\n  }\n\n  /**\n   * Sets the value of a `contenteditable` element.\n   * @param value Value to be set on the element.\n   */\n  async setContenteditableValue(value: string): Promise<void> {\n    const contenteditableAttr = await this.getAttribute('contenteditable');\n\n    if (\n      contenteditableAttr !== '' &&\n      contenteditableAttr !== 'true' &&\n      contenteditableAttr !== 'plaintext-only'\n    ) {\n      throw new Error('setContenteditableValue can only be called on a `contenteditable` element.');\n    }\n\n    await this._stabilize();\n    return this._executeScript(\n      (element: Element, valueToSet: string) => (element.textContent = valueToSet),\n      this.element(),\n      value,\n    );\n  }\n\n  /** Gets the value for the given attribute from the element. */\n  async getAttribute(name: string): Promise<string | null> {\n    await this._stabilize();\n    return this._executeScript(\n      (element: Element, attribute: string) => element.getAttribute(attribute),\n      this.element(),\n      name,\n    );","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/testing/selenium-webdriver/selenium-web-driver-element.ts#L145-L181","documentation":"SeleniumWebDriverElement.setContenteditableValue in src/cdk/testing/selenium-webdriver/selenium-web-driver-element.ts guards the same way as the Protractor variant: it reads the contenteditable attribute and throws this Error if the element is not editable (attribute missing or not ''/true/plaintext-only). Only editable elements may have their textContent set through this API; it then executes the set script and stabilizes the harness environment.","triggerScenarios":"Calling setContenteditableValue on a Selenium-WebDriver-backed TestElement where the DOM node has no contenteditable attribute or contenteditable=\"false\" — e.g. targeting an <input>, a <textarea>, or a div whose editability is toggled off.","commonSituations":"E2E suites mixing up form control APIs with contenteditable APIs; testing custom editors where contenteditable is applied conditionally (e.g. only in edit mode); stale element references captured before the attribute was applied.","solutions":["Verify the element has contenteditable=\"true\"/\"plaintext-only\" at the time of the call (check via getAttribute('contenteditable')).","For inputs/textareas use sendKeys or the appropriate input-value APIs instead of setContenteditableValue.","If editability is conditional, put the component into edit mode (or wait for the attribute) before invoking the method.","Re-query the element after DOM updates so you operate on the current editable node."],"exampleFix":"// before\nawait element.setContenteditableValue('updated text');\n// after\nif ((await element.getAttribute('contenteditable')) === 'true') {\n  await element.setContenteditableValue('updated text');\n}","handlingStrategy":"validation","validationCode":"const editable = await element.getAttribute('contenteditable');\nif (editable !== 'true' && editable !== 'plaintext-only' && editable !== '') {\n  throw new Error(`Cannot setContenteditableValue: contenteditable=\"${editable}\"`);\n}","typeGuard":"function isEditable(v: string | null): v is 'true' | 'plaintext-only' | '' {\n  return v === 'true' || v === 'plaintext-only' || v === '';\n}","tryCatchPattern":"try {\n  await element.setContenteditableValue(value);\n} catch (e) {\n  if (String(e.message).includes('setContenteditableValue can only be called')) {\n    console.warn('Target is not contenteditable; falling back to sendKeys.');\n    await element.sendKeys(value);\n  } else throw e;\n}","preventionTips":["Ensure the component applies contenteditable before the E2E step runs (wait for edit mode).","Use explicit attribute waits/expectations in Selenium flows before editing text.","Keep separate helper methods for form controls vs contenteditable regions.","Re-locate elements after DOM changes to avoid stale, non-editable references."],"tags":["angular","cdk-testing","selenium-webdriver","contenteditable"],"backgroundTag":"invalid-element-state","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}