# Make an HTML element editable with the contenteditable attribute

You can make the contents of an HTML element editable, much like the text in a
form field, by adding the
[`contenteditable`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/contenteditable)
attribute.

```html
<div id="editable-div" contenteditable="true">Hello!</div>
```

You can edit that div 👇

[Interactive example](/make-any-html-element-editable)

`contenteditable` is an enumerated attribute rather than a Boolean attribute. It
accepts these values:

- `true` or an empty value makes the element editable
- `false` makes the element non-editable
- `plaintext-only` allows editing but disables rich-text formatting

If the attribute is missing or has an invalid value, its value is inherited from
the parent. With `contenteditable="true"`, pasted formatting is retained; with
`contenteditable="plaintext-only"`, the browser removes it.

## Listening for changes on a `contenteditable` element

A `contenteditable` element has no `value` property, and the `change` event used
with form fields is not the right event here. Listen for the `input` event and
read the element's text instead:

```js
const editableDiv = document.getElementById('editable-div')

if (editableDiv === null) {
  throw new Error('Editable div not found')
}

editableDiv.addEventListener('input', event => {
  console.log(event.currentTarget.innerText)
})
```

Notice that `getElementById()` receives `editable-div`, without the `#` used in
a CSS selector. Use `innerText` when you want the rendered plain text. Use
`innerHTML` only when you intentionally need the element's markup.

The related
[`beforeinput` event](https://developer.mozilla.org/en-US/docs/Web/API/Element/beforeinput_event)
fires before the browser changes the DOM. It is useful when an editor needs to
inspect or override an edit.

Older examples often use `document.execCommand()` for formatting and clipboard
operations. The method is deprecated and inconsistently implemented, so do not
build a new editor around it. For clipboard operations, use the Clipboard API.

[how to copy text with the Clipboard API](/copying-text-with-javascript)

## A `contenteditable` React component

React warns when a `contentEditable` element also has children managed by React:

![Error message from JavaScript console](/images/contenteditable-error-react.png)

Warning: A component is `contentEditable` and contains `children` managed by React. It is now your responsibility to guarantee that none of those nodes are unexpectedly modified or duplicated. This is probably not intentional.

The warning is correct: `Hello!` is a child, even though it is only a text node.
The browser can modify that child while React assumes it owns the same DOM.

For a small plain-text editor, you can deliberately leave the editable DOM
uncontrolled, mirror its text into state, and suppress the warning:

```jsx
import { useState } from 'react'

function EditableDiv() {
  const [divText, setDivText] = useState('Hello!')

  return (
    <>
      <div
        aria-label='Editable text'
        aria-multiline='true'
        className='pink-div'
        contentEditable='plaintext-only'
        onInput={event => setDivText(event.currentTarget.innerText)}
        role='textbox'
        suppressContentEditableWarning
      >
        Hello!
      </div>
      <div className='value-container'>
        <strong>Value:</strong> {divText}
      </div>
    </>
  )
}
```

This example displays the current text elsewhere, but it does not render
`divText` back into the editable element. Replacing the element's children on
every keystroke can reset the caret or selection. A full rich-text editor also
has to manage selections, undo history, pasted content, and browser differences,
so a tested editor library is usually a better starting point.

## Accessibility, forms, and security

Prefer an `<input>` or `<textarea>` when you only need a normal text field. They
provide built-in semantics, validation, and form submission. A `contenteditable`
element is focusable, but it is not a form control and its contents are not
submitted automatically.

If it acts as a text field, give it an accessible name and `role="textbox"`. Add
`aria-multiline="true"` when Enter inserts a new line, as in the React example
above.

Finally, treat editable HTML as untrusted input. Rich content can contain markup
introduced through pasting or editing, so sanitize it before saving or rendering
it. `plaintext-only` is the safer choice when formatting is unnecessary, but it
does not replace server-side validation.

## Conclusions

`contenteditable` is useful for inline renaming, editable demos, and as a
building block for rich-text editors. For ordinary plain-text input, native form
controls are simpler and more robust.
