> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ueberdosis/tiptap/llms.txt
> Use this file to discover all available pages before exploring further.

# EditorContent

> React component for rendering the Tiptap editor content

## Overview

The `EditorContent` component is responsible for rendering the actual editor interface where users can interact with content. It must be used in conjunction with the `useEditor` hook.

## Type Signature

```typescript theme={null}
const EditorContent: React.ForwardRefExoticComponent<
  EditorContentProps & React.RefAttributes<HTMLDivElement>
>

interface EditorContentProps extends HTMLProps<HTMLDivElement> {
  editor: Editor | null
  innerRef?: ForwardedRef<HTMLDivElement | null>
}
```

## Props

<ParamField path="editor" type="Editor | null" required>
  The editor instance created by the `useEditor` hook. Can be `null` during initialization.
</ParamField>

<ParamField path="...props" type="HTMLProps<HTMLDivElement>">
  All standard HTML div attributes are supported and will be passed to the wrapper element. This includes:

  * `className` - CSS class names
  * `style` - Inline styles
  * `id` - Element ID
  * `onClick`, `onFocus`, etc. - Event handlers
  * Any other valid div attributes
</ParamField>

## Ref Forwarding

The component supports ref forwarding, allowing you to get a reference to the underlying `HTMLDivElement`:

```tsx theme={null}
import { useRef } from 'react'
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editorRef = useRef<HTMLDivElement>(null)
  const editor = useEditor({
    extensions: [StarterKit],
  })

  return <EditorContent ref={editorRef} editor={editor} />
}
```

## Usage Examples

### Basic Usage

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Hello World!</p>',
  })

  return <EditorContent editor={editor} />
}
```

### With Custom Styling

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Hello World!</p>',
  })

  return (
    <EditorContent
      editor={editor}
      className="prose max-w-none"
      style={{
        minHeight: '200px',
        border: '1px solid #ccc',
        borderRadius: '8px',
        padding: '16px',
      }}
    />
  )
}
```

### With Loading State

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Hello World!</p>',
    immediatelyRender: false,
  })

  if (!editor) {
    return (
      <div className="editor-loading">
        <p>Loading editor...</p>
      </div>
    )
  }

  return <EditorContent editor={editor} />
}
```

### Multiple Editors

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editor1 = useEditor({
    extensions: [StarterKit],
    content: '<p>Editor 1</p>',
  })

  const editor2 = useEditor({
    extensions: [StarterKit],
    content: '<p>Editor 2</p>',
  })

  return (
    <div>
      <EditorContent editor={editor1} className="editor-1" />
      <EditorContent editor={editor2} className="editor-2" />
    </div>
  )
}
```

### With Click Handler

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Click on me!</p>',
  })

  const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
    console.log('Editor clicked', event)
  }

  return (
    <EditorContent
      editor={editor}
      onClick={handleClick}
    />
  )
}
```

### Combining with Toolbar

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

function MyEditor() {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Hello World!</p>',
  })

  if (!editor) {
    return null
  }

  return (
    <div className="editor-container">
      <div className="toolbar">
        <button onClick={() => editor.chain().focus().toggleBold().run()}>
          Bold
        </button>
        <button onClick={() => editor.chain().focus().toggleItalic().run()}>
          Italic
        </button>
      </div>
      <EditorContent
        editor={editor}
        className="editor-content"
      />
    </div>
  )
}
```

## Styling

### CSS Classes

The editor content is wrapped in a div that you can style. The actual ProseMirror editor will be nested inside:

```css theme={null}
/* Your wrapper div */
.my-editor {
  border: 1px solid #ccc;
  border-radius: 8px;
}

/* ProseMirror editor */
.my-editor .ProseMirror {
  padding: 16px;
  min-height: 200px;
  outline: none;
}

/* Focus styles */
.my-editor .ProseMirror:focus {
  outline: none;
}

/* Content styles */
.my-editor .ProseMirror p {
  margin: 0 0 1em;
}

.my-editor .ProseMirror h1 {
  font-size: 2em;
  font-weight: bold;
}
```

### Tailwind CSS

```tsx theme={null}
<EditorContent
  editor={editor}
  className="
    prose
    max-w-none
    rounded-lg
    border
    border-gray-300
    p-4
    focus-within:border-blue-500
    focus-within:ring-2
    focus-within:ring-blue-200
  "
/>
```

## Important Notes

<Note>
  The `EditorContent` component uses React portals internally to render node views. This ensures that React components used in custom node views maintain their context and state properly.
</Note>

<Warning>
  Do not conditionally render `EditorContent` based on the editor instance. Instead, handle the loading state by checking if the editor is null before rendering your component, or show a loading indicator.
</Warning>

<Tip>
  You can render multiple `EditorContent` components with the same editor instance, but this is generally not recommended as it can lead to unexpected behavior. Each editor instance should typically have one content component.
</Tip>

## Behavior

### Mounting and Unmounting

* When mounted, `EditorContent` attaches the ProseMirror view to the DOM
* When unmounted, it properly cleans up the view and removes event listeners
* The editor instance itself is not destroyed when `EditorContent` unmounts

### Node Views

`EditorContent` automatically manages React-based node views:

* Node views are rendered using React portals
* They maintain full React context (hooks, context API, etc.)
* Updates are synchronized with the editor state

## Related

* [useEditor](/api/react/use-editor) - Hook for creating the editor instance
* [BubbleMenu](/api/react/bubble-menu) - Contextual menu component
* [FloatingMenu](/api/react/floating-menu) - Floating menu component
* [Editor](https://tiptap.dev/docs/editor/api/editor) - Core editor API
