diff --git a/demos/src/Examples/CustomDocument/React/index.html b/demos/src/Examples/CustomDocument/React/index.html
new file mode 100644
index 000000000..289c03e93
--- /dev/null
+++ b/demos/src/Examples/CustomDocument/React/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/src/Examples/CustomDocument/React/index.jsx b/demos/src/Examples/CustomDocument/React/index.jsx
new file mode 100644
index 000000000..b00bc992f
--- /dev/null
+++ b/demos/src/Examples/CustomDocument/React/index.jsx
@@ -0,0 +1,42 @@
+import React from 'react'
+import { useEditor, EditorContent } from '@tiptap/react'
+import Document from '@tiptap/extension-document'
+import Placeholder from '@tiptap/extension-placeholder'
+import StarterKit from '@tiptap/starter-kit'
+import './styles.scss'
+
+const CustomDocument = Document.extend({
+ content: 'heading block*',
+})
+
+export default () => {
+ const editor = useEditor({
+ extensions: [
+ CustomDocument,
+ StarterKit.configure({
+ document: false,
+ }),
+ Placeholder.configure({
+ placeholder: ({ node }) => {
+ if (node.type.name === 'heading') {
+ return 'What’s the title?'
+ }
+
+ return 'Can you add some further context?'
+ },
+ }),
+ ],
+ content: `
+
+ It’ll always have a heading …
+
+
+ … if you pass a custom document. That’s the beauty of having full control over the schema.
+
+ `,
+ })
+
+ return (
+
+ )
+}
diff --git a/demos/src/Examples/CustomDocument/React/styles.scss b/demos/src/Examples/CustomDocument/React/styles.scss
new file mode 100644
index 000000000..85f390477
--- /dev/null
+++ b/demos/src/Examples/CustomDocument/React/styles.scss
@@ -0,0 +1,24 @@
+/* Basic editor styles */
+.ProseMirror {
+ > * + * {
+ margin-top: 0.75em;
+ }
+}
+
+/* Placeholder (at the top) */
+/*.ProseMirror p.is-editor-empty:first-child::before {
+ content: attr(data-placeholder);
+ float: left;
+ color: #ced4da;
+ pointer-events: none;
+ height: 0;
+}*/
+
+/* Placeholder (on every new line) */
+.ProseMirror .is-empty::before {
+ content: attr(data-placeholder);
+ float: left;
+ color: #ced4da;
+ pointer-events: none;
+ height: 0;
+}
diff --git a/demos/src/Examples/CustomDocument/Vue/index.html b/demos/src/Examples/CustomDocument/Vue/index.html
new file mode 100644
index 000000000..2b250c872
--- /dev/null
+++ b/demos/src/Examples/CustomDocument/Vue/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/src/Examples/CustomDocument/Vue/index.spec.js b/demos/src/Examples/CustomDocument/Vue/index.spec.js
new file mode 100644
index 000000000..1240629a5
--- /dev/null
+++ b/demos/src/Examples/CustomDocument/Vue/index.spec.js
@@ -0,0 +1,7 @@
+context('/src/Examples/CustomDocument/Vue/', () => {
+ before(() => {
+ cy.visit('/src/Examples/CustomDocument/Vue/')
+ })
+
+ // TODO: Write tests
+})
diff --git a/demos/src/Examples/CustomDocument/Vue/index.vue b/demos/src/Examples/CustomDocument/Vue/index.vue
new file mode 100644
index 000000000..23d2ce55b
--- /dev/null
+++ b/demos/src/Examples/CustomDocument/Vue/index.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
diff --git a/docs/examples/custom-document.md b/docs/examples/custom-document.md
new file mode 100644
index 000000000..1d0213fb2
--- /dev/null
+++ b/docs/examples/custom-document.md
@@ -0,0 +1,3 @@
+# Custom Document
+
+
diff --git a/docs/links.yaml b/docs/links.yaml
index 8a7dd4a91..b7873d290 100644
--- a/docs/links.yaml
+++ b/docs/links.yaml
@@ -84,6 +84,8 @@
link: /examples/suggestions
- title: Minimal setup
link: /examples/minimal
+ - title: Force a title
+ link: /examples/custom-document
- title: A clever editor
link: /examples/savvy
- title: Interactivity