This specification defines allowed values and expected behaviors for the {{ElementContentEditable/contentEditable}} attribute. This specification builds on [[HTML]].

This specification defines additional values for the {{ElementContentEditable/contentEditable}} attribute which is already defined by [[HTML]].

This is a work in progress.

Problems solved

Creating a web-based text-editor requires a considerable amount of JavaScript on top of the browser code, among other things because:

  1. Browsers differ in the manner they handle editing operations.
  2. Individual sites may have custom preferences for how they want to handle certain editing operations.
  3. The development of high-level text editing features in browsers has not followed the principles laid out in the [[[EXTENSIBLE]]] in that development of these features has not always been in coordination with the needs of the web developer community.

This spec seeks to alleviate the problem by providing a simple way for web developers prevent all browser default handling of editing operations at different levels without having to preventDefault each of them.

Use cases

  1. Creating a JavaScript text editor in which the [^strong^] element is used instead of the [^b^] element to mark text that the user marks as bold, using any browser-builtin way to mark a text as bold, without having access to all existing browsers.
  2. Creating a JavaScript text editor which works with a data model in the background where JavaScript takes care of rendering changes to the edited text to the DOM.
  3. Creating a JavaScript editor which only allows a subset of rich-text editing (for example: bold is allowed, but italic not).
  4. Creating a collaborative editor in which JavaScript is used to render changes to the DOM, based on user intentions with users using different browsers with different ways of expressing specific intentions.
  5. Creating a JavaScript editor with different user access options, where some users only can add or delete text and other users only can add or remove certain types of formatting.
  6. Creating a JavaScript editor in which caret movement is handled differently from the default.
  7. Creating a JavaScript editor with advanced elements, such as non-editable regions, inline SVGs, canvas-elements and other elements for which `contenteditable=true` currently creates caret placement issues in several browsers.

Terminology

Editing host
An editing host is a node that is an HTML element with a {{ElementContentEditable/contentEditable}} attribute set to something else than the `false` state.
`contentEditable=false` element
Any element that has the {{ElementContentEditable/contentEditable}} attribute set to `false`.
Inline elements
All element nodes for whom the used value of the `display` property resolves to the value `inline`.
Block elements
All element nodes for whom the used value of the `display` property resolves to the value `block`.
Stub elements
All element nodes that are void elements OR root elements using a different namespace than their parent elements (such as SVGs).
Invisible elements
All element nodes for whom the used value of the `display` property resolves to the value `none`.
Legal Caret Positions

All positions in which the caret can be placed programmatically. The placement is restricted to the following positions. Implementations MUST be able to place the caret in all of the following positions:

  1. Before or after any character in any text node.
  2. After inline elements that do not have a [=tree/next sibling=] which is a text node.
  3. Before inline elements that that do not have a [=tree/previous sibling=].
  4. Inside empty inline elements and block elements that are not stub elements.
  5. Inside empty text nodes.
  6. Before or after block elements that are also stub elements.
  7. Before or after comment nodes.
  8. In the editing host itself, if it is empty.

There are some exceptions to these rules:

  1. Within a table, the caret can only be placed inside [^th^], [^td^] and [^caption^] elements.
  2. The caret cannot be placed inside invisible elements.
  3. The caret cannot be placed inside elements whose contentEditable attribute returns `false`.

`contenteditable`

The contenteditable attribute is an enumerated attribute whose keywords are the empty string (""), "events", "caret", "typing", "plaintext-only", "true", and "false". There is one additional state, the `inherit` state, which is the missing value default (and the invalid value default).

The empty string and the "true" keyword map to the `true` state. The other keywords map to their respective states.

The `false` state indicates that the element is not editable. The `inherit` state indicates that the element has the state of its parent.

The contentEditable IDL attribute, on getting, must return the string "true" if the content attribute is set to the `true` state, "plaintext-only" if the content attribute is set to the `plaintext-only` state, "typing" if the content attribute is set to the `typing` state, "caret" if the content attribute is set to the `caret` state, "events" if the content attribute is set to the `events` state, "false" if the content attribute is set to the `false` state, and `inherit` otherwise.

On setting, if the new value is an ASCII case-insensitive match for the string "inherit" then the content attribute must be removed, if the new value is an ASCII case-insensitive match for a string matching the name of a state, then the content attribute must be set to the name of that state, and otherwise the attribute setter must throw a SyntaxError exception.

The isContentEditable IDL attribute, on getting, must return true if the element is either an editing host or editable, and false otherwise.

Meaning of states

The states "events", "caret", "typing", "plaintext-only" and "true" are hierarchically ordered, so that the state "caret" also includes the features of the "events" state, the "typing" state includes the features of the "caret" state, the "plaintext-only" state includes the features of the "typing" state, and the "true" state includes all the features of the "plaintext-only" state.

The "events" state means that beforeinput events are triggered when the user asks for an editing operation. The "caret" state adds default browser controlled movement of the caret. The "typing" state adds handling of text input through IME and keyboard, and deletion within an IME composition. The "plaintext-only" state adds handling of text deletion within a text node. The "true" state adds handling of deletion deletion of non-textual content and editing commands through the execCommand command.

The states "events", "caret", "typing" and "plaintext-only" are defined in this document.

The state "true" is currently not well-defined and its usage is discouraged. An initial attempt has been made to specify the behavior of the "true" state in the contentEditable=True spec.

contentEditable states

contentEditable=events state

In a focused editing host that is in the "events" state, a caret MUST be drawn if the selection is collapsed, and it MUST be possible to place the caret in all of the Legal Caret Positions programmatically.

All user editing intentions initiated while an editing host that is in the events state is focused, MUST trigger a `beforeinput` event.

contentEditable=caret state

A focused editing host that is in the "caret" state MUST behave like an editing host in the events state. Additionally, the default action of the `beforeSelectionChange` event in such an editing host must be to move the caret in the indicated direction, if movement in that direction seems possible.

Notice the planned beforeSelectionChange event.

contentEditable=typing state

A focused editing host that is in the "typing" state MUST behave like an editing host in the caret state, and additionally, it MUST handle text insertion by keyboard at the position of the caret if the caret is placed within a text node or it is possible to place a text node at the place of the caret. It must by default also handle composition by IME, both insertion as well as deletion of text input.

contentEditable=plaintext-only state

A focused editing host that is in the "plaintext-only" state MUST behave like an editing host in the typing state, and additionally, it MUST handle text deletion.

Cutting and pasting

Within an editing host that is in the "events", "caret" or "typing" state, cutting and pasting is disabled. Within an editing host in the "plaintext-only" state, pasting only causes plaintext pasting by default. Independently of the state of the editing host, the events `paste` and `cut` should be triggered whenever the user expresses the intention to paste or cut.

Caret drawing and movement

Caret drawing

A caret is drawn in any editing host that is focused, that does not hold any other selections. Under such conditions, the caret represents a collapsed selection.

Caret positions

It MUST be possible to put the caret in any of the Legal Caret Positions programmatically and for the caret to be visible in these in any editing host that is in the "events", "caret" or "typing" state.

Initial caret placement

Carets are initially placed at the first possible position within the editing host.

Caret movement

The specific location that the caret is moved to by default in an editing host in the "caret" and "typing" state, is out of scope for this specification, but later versions of this specification or specifications covering other contentEditable specifications may further specify the movement patterns of the caret.

Replacing text/content

When the user indicates the wish to replace part of the contents of a editing host, by means of a browser-builtin spell checker or alike, a `beforeinput` input with `inputType` set to `replaceText` or `replaceContent` is triggered. No part of the DOM is being changed by default in an editing host that is in the "events", "caret" or "typing" state.

Removal of content

Content is not removed automatically through user input in an editing host that is in the "events" or "caret" state. Instead, Del/Backspace key presses, etc. trigger user `beforeinput` events with `inputType` set to `deleteContentForward` or `deleteContentBackward`. The same is true for any editing host that is in the "typing" state, unless it is currently in the composition mode, in which case it will remove characters from the DOM if they are part of the composition.

In the "plaintext-only" state, an editing host does handle text deletion within a single text node.

Advanced grammar checking

An implementation MAY provide spell check, grammar check and other advanced functionality that are not defined through a specification for any editing host. These features MUST be disabled by default.

Context menu

If the implementation provides a `context menu`, this `context menu` SHOULD contain items for editing operations such as `paste`, `cut`, `copy`, `delete` and CAN contain items for spellchecking for any editing host. Triggering any of `context menu` items MUST NOT by default cause any change to the DOM, `paste`, `cut` and `beforeinput` events SHOULD be triggered. Menu items in a `context menu` that do not cause DOM changes by default SHOULD function as in any other editing context.

Privacy and Security Considerations

To be written.

Accessibility Considerations

To be written.

Acknowledgements

Thanks to: Michael Aufreiter, Adrian Bateman, Robin Berjon, Oliver Buchtala, Enrica Casucci, Olivier Forget, Aryeh Gregor, Marijn Haverbeke, Xiaocheng Hu, Yoshifumi Inoue, Koji Ishii, Gary Kacmarcik, Frederico Caldeira Knabben, Takayoshi Kochi, Piotrek Koszuliński, Travis Leithead, Grisha Lyukshin, Chaals McCathie Nevile, Masayuki Nakano, Ryosuke Niwa, Julie Parent, Ben Peters, Florian Rivoal, Hallvord R. M. Steen, Johan Sörlin, Cristian Talau, Ojan Vafai, Xiaoqian Wu, Chong Zhang, Joanmarie, and everyone in the Editing Taskforce for their input and feedback.