---
title: "Whiteboard doc frames"
description: "Show rich text documents on a whiteboard. Each doc frame holds a document in an editor of its own, and your app keeps the documents."
canonical_url: "https://tiptap.dev/docs/editor/whiteboard/guides/doc-frames"
---

# Whiteboard doc frames

Show rich text documents on a whiteboard. Each doc frame holds a document in an editor of its own, and your app keeps the documents.

A doc frame is a shape that shows a rich text document, in an editor of its own. The board stores the frame and the id of its document. Your app keeps the documents, so the board stays free of any storage.

## Provide the documents

Tell the board where the documents live with the `docs` option of `WhiteboardKit`. Without it, doc frames show no document. This example keeps the documents in memory:

```js
import { Editor } from '@tiptap/core'
import { StarterKit } from '@tiptap/starter-kit'
import { WhiteboardKit } from '@tiptap-pro/extension-whiteboard'

// Document JSON by document id
const documents = new Map()

const editor = new Editor({
  element: viewport,
  extensions: [
    WhiteboardKit.configure({
      docs: {
        createEditor: ({ element, docId }) =>
          new Editor({
            element,
            extensions: [StarterKit],
            content: documents.get(docId),
            onUpdate: ({ editor: docEditor }) => documents.set(docId, docEditor.getJSON()),
          }),
        copy: ({ fromDocId, toDocId }) => {
          const document = documents.get(fromDocId)

          if (document) {
            documents.set(toDocId, structuredClone(document))
          }
        },
        load: ({ docId, content }) => documents.set(docId, content),
      },
    }),
  ],
})
```

In React, create the configured kit once, outside the component or with `useMemo`. See [Set up a board in React](https://tiptap.dev/docs/editor/whiteboard/guides/react.md).

The `docs` object has these members:

- `createEditor({ element, docId })` creates the editor of a document inside `element`, the frame's content element, `[data-shape-content]`. The board destroys the editor with its frame. The editor can have any extensions, like `StarterKit`.
- `copy({ fromDocId, toDocId })` copies a document for the copy of its frame, when a user duplicates or pastes the frame. It runs before the copy shows.
- `load({ docId, content })`, which is optional, fills the new document of a frame that [`importBoard`](https://tiptap.dev/docs/editor/whiteboard/guides/export-and-import.md#doc-frames) adds from a board file. It runs before the frame shows. Without it, imported frames start empty.
- `start(docId)`, which is optional, starts the document of every frame that a change in this editor brings onto the board: a new frame, a copy, and also frames that `setContent` or an undo with `UndoRedo` bring back. It runs before the frame shows. Frames that come through Yjs, from other editors or from its undo, don't start a document here.

So `start` also runs for frames whose document exists already, like a copy, after `copy`. Keep a document that the frame already has:

```js
start: (docId) => {
  if (!documents.has(docId)) {
    documents.set(docId, { type: 'doc', content: [{ type: 'paragraph' }] })
  }
},
```

## Add a doc frame

The `doc` tool, key W, adds a frame with a new document and starts editing it. Without `docs`, the board has no `doc` tool. In code, add a frame like any other shape:

```js
import { createShapeId } from '@tiptap-pro/extension-whiteboard'

editor.commands.insertShape({ type: 'docFrame', docId: createShapeId(), x: 0, y: 0, width: 420 })
```

The frame shows the document with the id in `docId`. A frame without a `docId` uses its own shape id, so it still gets a document of its own. `docIdOf` returns the id of a frame's document, from its node or the node's JSON.

## Edit a document

The board selects, moves and resizes a frame like other shapes. Its height follows its document. The editor of the document is read-only until editing starts: with a click on the selected frame, with Enter, or with `editShapeText`:

```js
editor.commands.editShapeText({ id: 'frame' })
```

While the document is edited, presses and keys inside the frame belong to its editor. Escape stops editing and selects the frame again. A press on another shape stops editing, too, and so does [making the board read-only](https://tiptap.dev/docs/editor/whiteboard/guides/shapes-and-tools.md#read-only-boards).

### Format the edited document

Your toolbar can work on the edited document and on the text of shapes alike. `getEditedDocEditor` returns the editor of the document that a frame edits, or `null` while none is edited:

```js
import { getEditedDocEditor } from '@tiptap-pro/extension-whiteboard'

// A bold button that works in documents too
const textEditor = getEditedDocEditor(editor) ?? editor
textEditor.commands.toggleBold()
```

The board's editor emits `docChange` on every transaction of a document's editor, also one that only moves the caret, when its editing starts or stops, and when its editor is created or destroyed. Use it to update the toolbar, but not to save documents:

```js
editor.on('docChange', ({ docId }) => {
  console.log(`The document ${docId} changed`)
})
```

## Read all documents

`getDocEditors` returns the editors of the documents that the frames on the board show:

```js
import { getDocEditors } from '@tiptap-pro/extension-whiteboard'

const contents = getDocEditors(editor).map((docEditor) => docEditor.getJSON())
```

It returns no editors once the board's editor is destroyed.

## Documents that arrive later

A frame grows as tall as its document after each change in this editor. Other users' editors measure the changes that they make. When the document arrives after the frame, like when an AI adds a frame and writes its document later, keep the height that you gave the frame with `keepShapeHeights`:

```js
import { keepShapeHeights } from '@tiptap-pro/extension-whiteboard'

const { tr } = editor.state
// … add a doc frame whose document arrives later
editor.view.dispatch(keepShapeHeights(tr))
```

## Next steps

- Edit a board together with [collaboration](https://tiptap.dev/docs/editor/whiteboard/guides/collaboration.md)
- Save a board with its documents to a file with [export and import](https://tiptap.dev/docs/editor/whiteboard/guides/export-and-import.md)
- See the [`BoardDocs` type](https://tiptap.dev/docs/editor/whiteboard/api-reference/types.md#boarddocs)
