angular/components · error · Error

setContenteditableValue can only be called on a `contentedit

Error message

setContenteditableValue can only be called on a `contenteditable` element.

What it means

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.

Source

Thrown at src/cdk/testing/selenium-webdriver/selenium-web-driver-element.ts:163

    return this._executeScript(
      (element: Element) => (element.textContent || '').trim(),
      this.element(),
    );
  }

  /**
   * Sets the value of a `contenteditable` element.
   * @param value Value to be set on the element.
   */
  async setContenteditableValue(value: string): Promise<void> {
    const contenteditableAttr = await this.getAttribute('contenteditable');

    if (
      contenteditableAttr !== '' &&
      contenteditableAttr !== 'true' &&
      contenteditableAttr !== 'plaintext-only'
    ) {
      throw new Error('setContenteditableValue can only be called on a `contenteditable` element.');
    }

    await this._stabilize();
    return this._executeScript(
      (element: Element, valueToSet: string) => (element.textContent = valueToSet),
      this.element(),
      value,
    );
  }

  /** Gets the value for the given attribute from the element. */
  async getAttribute(name: string): Promise<string | null> {
    await this._stabilize();
    return this._executeScript(
      (element: Element, attribute: string) => element.getAttribute(attribute),
      this.element(),
      name,
    );

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Verify the element has contenteditable="true"/"plaintext-only" at the time of the call (check via getAttribute('contenteditable')).
  2. For inputs/textareas use sendKeys or the appropriate input-value APIs instead of setContenteditableValue.
  3. If editability is conditional, put the component into edit mode (or wait for the attribute) before invoking the method.
  4. Re-query the element after DOM updates so you operate on the current editable node.

Example fix

// before
await element.setContenteditableValue('updated text');
// after
if ((await element.getAttribute('contenteditable')) === 'true') {
  await element.setContenteditableValue('updated text');
}
Defensive patterns

Strategy: validation

Validate before calling

const editable = await element.getAttribute('contenteditable');
if (editable !== 'true' && editable !== 'plaintext-only' && editable !== '') {
  throw new Error(`Cannot setContenteditableValue: contenteditable="${editable}"`);
}

Type guard

function isEditable(v: string | null): v is 'true' | 'plaintext-only' | '' {
  return v === 'true' || v === 'plaintext-only' || v === '';
}

Try / catch

try {
  await element.setContenteditableValue(value);
} catch (e) {
  if (String(e.message).includes('setContenteditableValue can only be called')) {
    console.warn('Target is not contenteditable; falling back to sendKeys.');
    await element.sendKeys(value);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/a7b2691dae663085. Report an issue: GitHub.