diff --git a/demos/src/Nodes/HorizontalRule/React/index.html b/demos/src/Nodes/HorizontalRule/React/index.html
new file mode 100644
index 00000000..22ce8688
--- /dev/null
+++ b/demos/src/Nodes/HorizontalRule/React/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/src/Nodes/HorizontalRule/React/index.jsx b/demos/src/Nodes/HorizontalRule/React/index.jsx
new file mode 100644
index 00000000..9c706957
--- /dev/null
+++ b/demos/src/Nodes/HorizontalRule/React/index.jsx
@@ -0,0 +1,34 @@
+import React from 'react'
+import { useEditor, EditorContent } from '@tiptap/react'
+import Document from '@tiptap/extension-document'
+import Paragraph from '@tiptap/extension-paragraph'
+import Text from '@tiptap/extension-text'
+import HorizontalRule from '@tiptap/extension-horizontal-rule'
+import './styles.scss'
+
+export default () => {
+ const editor = useEditor({
+ extensions: [Document, Paragraph, Text, HorizontalRule],
+ content: `
+ This is a paragraph.
+
+ And this is another paragraph.
+
+ But between those paragraphs are horizontal rules.
+ `,
+ })
+
+ if (!editor) {
+ return null
+ }
+
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/demos/src/Nodes/HorizontalRule/React/index.spec.js b/demos/src/Nodes/HorizontalRule/React/index.spec.js
new file mode 100644
index 00000000..340806df
--- /dev/null
+++ b/demos/src/Nodes/HorizontalRule/React/index.spec.js
@@ -0,0 +1,57 @@
+context('/src/Nodes/HorizontalRule/React/', () => {
+ before(() => {
+ cy.visit('/src/Nodes/HorizontalRule/React/')
+ })
+
+ beforeEach(() => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ })
+ })
+
+ it('should parse horizontal rules correctly', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ expect(editor.getHTML()).to.eq('Example Text
')
+ })
+ })
+
+ it('should parse horizontal rules with self-closing tag correctly', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ expect(editor.getHTML()).to.eq('Example Text
')
+ })
+ })
+
+ it('the button should add a horizontal rule', () => {
+ cy.get('.ProseMirror hr').should('not.exist')
+
+ cy.get('button:first').click()
+
+ cy.get('.ProseMirror hr').should('exist')
+ })
+
+ it('the default markdown shortcut should add a horizontal rule', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror hr').should('not.exist')
+
+ cy.get('.ProseMirror').type('---')
+
+ cy.get('.ProseMirror hr').should('exist')
+ })
+ })
+
+ it('the alternative markdown shortcut should add a horizontal rule', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror hr').should('not.exist')
+
+ cy.get('.ProseMirror').type('___ ')
+
+ cy.get('.ProseMirror hr').should('exist')
+ })
+ })
+})
diff --git a/demos/src/Nodes/HorizontalRule/React/styles.scss b/demos/src/Nodes/HorizontalRule/React/styles.scss
new file mode 100644
index 00000000..bfd53e2a
--- /dev/null
+++ b/demos/src/Nodes/HorizontalRule/React/styles.scss
@@ -0,0 +1,3 @@
+hr.ProseMirror-selectednode {
+ border-top: 1px solid #68cef8;
+}