diff --git a/demos/src/Nodes/BulletList/React/index.html b/demos/src/Nodes/BulletList/React/index.html
new file mode 100644
index 00000000..bb3c7522
--- /dev/null
+++ b/demos/src/Nodes/BulletList/React/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/src/Nodes/BulletList/React/index.jsx b/demos/src/Nodes/BulletList/React/index.jsx
new file mode 100644
index 00000000..63a11249
--- /dev/null
+++ b/demos/src/Nodes/BulletList/React/index.jsx
@@ -0,0 +1,55 @@
+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 BulletList from '@tiptap/extension-bullet-list'
+import ListItem from '@tiptap/extension-list-item'
+import './styles.scss'
+
+export default () => {
+ const editor = useEditor({
+ extensions: [Document, Paragraph, Text, BulletList, ListItem],
+ content: `
+
+ - A list item
+ - And another one
+
+ `,
+ })
+
+ if (!editor) {
+ return null
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/demos/src/Nodes/BulletList/React/index.spec.js b/demos/src/Nodes/BulletList/React/index.spec.js
new file mode 100644
index 00000000..c0d58a4e
--- /dev/null
+++ b/demos/src/Nodes/BulletList/React/index.spec.js
@@ -0,0 +1,115 @@
+context('/src/Nodes/BulletList/React/', () => {
+ before(() => {
+ cy.visit('/src/Nodes/BulletList/React/')
+ })
+
+ beforeEach(() => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ cy.get('.ProseMirror').type('{selectall}')
+ })
+ })
+
+ it('should parse unordered lists correctly', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('')
+ expect(editor.getHTML()).to.eq('')
+ })
+ })
+
+ it('should parse unordered lists without paragraphs correctly', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('')
+ expect(editor.getHTML()).to.eq('')
+ })
+ })
+
+ it('the button should make the selected line a bullet list item', () => {
+ cy.get('.ProseMirror ul').should('not.exist')
+
+ cy.get('.ProseMirror ul li').should('not.exist')
+
+ cy.get('button:nth-child(1)').click()
+
+ cy.get('.ProseMirror').find('ul').should('contain', 'Example Text')
+
+ cy.get('.ProseMirror').find('ul li').should('contain', 'Example Text')
+ })
+
+ it('the button should toggle the bullet list', () => {
+ cy.get('.ProseMirror ul').should('not.exist')
+
+ cy.get('button:nth-child(1)').click()
+
+ cy.get('.ProseMirror').find('ul').should('contain', 'Example Text')
+
+ cy.get('button:nth-child(1)').click()
+
+ cy.get('.ProseMirror ul').should('not.exist')
+ })
+
+ it('should leave the list with double enter', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+
+ cy.get('.ProseMirror').type('- List Item 1{enter}{enter}Paragraph')
+
+ cy.get('.ProseMirror').find('li').its('length').should('eq', 1)
+
+ cy.get('.ProseMirror').find('p').should('contain', 'Paragraph')
+ })
+
+ it('should make the paragraph a bullet list keyboard shortcut is pressed', () => {
+ cy.get('.ProseMirror')
+ .trigger('keydown', { modKey: true, shiftKey: true, key: '8' })
+ .find('ul li')
+ .should('contain', 'Example Text')
+ })
+
+ it('should make a bullet list from an asterisk', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+
+ cy.get('.ProseMirror').type('* List Item 1{enter}List Item 2')
+
+ cy.get('.ProseMirror').find('li:nth-child(1)').should('contain', 'List Item 1')
+
+ cy.get('.ProseMirror').find('li:nth-child(2)').should('contain', 'List Item 2')
+ })
+
+ it('should make a bullet list from a dash', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+
+ cy.get('.ProseMirror').type('- List Item 1{enter}List Item 2')
+
+ cy.get('.ProseMirror').find('li:nth-child(1)').should('contain', 'List Item 1')
+
+ cy.get('.ProseMirror').find('li:nth-child(2)').should('contain', 'List Item 2')
+ })
+
+ it('should make a bullet list from a plus', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+
+ cy.get('.ProseMirror').type('+ List Item 1{enter}List Item 2')
+
+ cy.get('.ProseMirror').find('li:nth-child(1)').should('contain', 'List Item 1')
+
+ cy.get('.ProseMirror').find('li:nth-child(2)').should('contain', 'List Item 2')
+ })
+
+ it('should remove the bullet list after pressing backspace', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+ })
+
+ cy.get('.ProseMirror').type('* {backspace}Example')
+
+ cy.get('.ProseMirror').find('p').should('contain', '* Example')
+ })
+})
diff --git a/demos/src/Nodes/BulletList/React/styles.scss b/demos/src/Nodes/BulletList/React/styles.scss
new file mode 100644
index 00000000..d7d0f5ad
--- /dev/null
+++ b/demos/src/Nodes/BulletList/React/styles.scss
@@ -0,0 +1,11 @@
+/* Basic editor styles */
+.ProseMirror {
+ > * + * {
+ margin-top: 0.75em;
+ }
+
+ ul,
+ ol {
+ padding: 0 1rem;
+ }
+}