diff --git a/docs/src/demos/Experiments/GenericFigure/figcaption.ts b/docs/src/demos/Experiments/GenericFigure/figcaption.ts
new file mode 100644
index 000000000..dd9fb4738
--- /dev/null
+++ b/docs/src/demos/Experiments/GenericFigure/figcaption.ts
@@ -0,0 +1,27 @@
+import { Node, mergeAttributes } from '@tiptap/core'
+
+export const Figcaption = Node.create({
+ name: 'figcaption',
+
+ defaultOptions: {
+ HTMLAttributes: {},
+ },
+
+ content: 'inline*',
+
+ selectable: false,
+
+ draggable: false,
+
+ parseHTML() {
+ return [
+ {
+ tag: 'figcaption',
+ },
+ ]
+ },
+
+ renderHTML({ HTMLAttributes }) {
+ return ['figcaption', mergeAttributes(HTMLAttributes), 0]
+ },
+})
diff --git a/docs/src/demos/Experiments/GenericFigure/figure.ts b/docs/src/demos/Experiments/GenericFigure/figure.ts
new file mode 100644
index 000000000..198c4933d
--- /dev/null
+++ b/docs/src/demos/Experiments/GenericFigure/figure.ts
@@ -0,0 +1,56 @@
+import { Node, mergeAttributes } from '@tiptap/core'
+import { Plugin } from 'prosemirror-state'
+
+export const Figure = Node.create({
+ name: 'figure',
+
+ defaultOptions: {
+ HTMLAttributes: {},
+ },
+
+ group: 'block',
+
+ content: 'block figcaption',
+
+ draggable: true,
+
+ isolating: true,
+
+ parseHTML() {
+ return [
+ {
+ tag: `figure[data-type="${this.name}"]`,
+ },
+ ]
+ },
+
+ renderHTML({ HTMLAttributes }) {
+ return ['figure', mergeAttributes(HTMLAttributes, { 'data-type': this.name }), 0]
+ },
+
+ addProseMirrorPlugins() {
+ return [
+ new Plugin({
+ props: {
+ handleDOMEvents: {
+ // prevent dragging nodes out of the figure
+ dragstart: (view, event) => {
+ if (!event.target) {
+ return false
+ }
+
+ const pos = view.posAtDOM(event.target as HTMLElement, 0)
+ const $pos = view.state.doc.resolve(pos)
+
+ if ($pos.parent.type === this.type) {
+ event.preventDefault()
+ }
+
+ return false
+ },
+ },
+ },
+ }),
+ ]
+ },
+})
diff --git a/docs/src/demos/Experiments/GenericFigure/index.vue b/docs/src/demos/Experiments/GenericFigure/index.vue
new file mode 100644
index 000000000..ff3e80bb0
--- /dev/null
+++ b/docs/src/demos/Experiments/GenericFigure/index.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
diff --git a/docs/src/docPages/experiments.md b/docs/src/docPages/experiments.md
index 04595bc77..6c04894fc 100644
--- a/docs/src/docPages/experiments.md
+++ b/docs/src/docPages/experiments.md
@@ -5,6 +5,7 @@ Congratulations! You’ve found our playground with a list of experiments. Be aw
* [Linter](/experiments/linter)
* [Content of multiple editors in a single Y.js](/experiments/multiple-editors)
* [Global drag handle](/experiments/global-drag-handle)
+* [Generic Figure](/experiments/generic-figure)
## Experimental extensions
* [@tiptap/extension-command-menu](/experiments/commands)
diff --git a/docs/src/docPages/experiments/generic-figure.md b/docs/src/docPages/experiments/generic-figure.md
new file mode 100644
index 000000000..ae9c4c5fe
--- /dev/null
+++ b/docs/src/docPages/experiments/generic-figure.md
@@ -0,0 +1,5 @@
+# GenericFigure
+
+⚠️ Experiment
+
+