diff --git a/docs/src/demos/Marks/Subscript/index.spec.js b/docs/src/demos/Marks/Subscript/index.spec.js
new file mode 100644
index 00000000..58ebd939
--- /dev/null
+++ b/docs/src/demos/Marks/Subscript/index.spec.js
@@ -0,0 +1,42 @@
+context('/demos/Marks/Subscript', () => {
+ before(() => {
+ cy.visit('/demos/Marks/Subscript')
+ })
+
+ beforeEach(() => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('
Example Text
')
+ cy.get('.ProseMirror').type('{selectall}')
+ })
+ })
+
+ it('should transform inline style to sub tags', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ expect(editor.getHTML()).to.eq('Example Text
')
+ })
+ })
+
+ it('sould omit inline style with a different vertical align', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ expect(editor.getHTML()).to.eq('Example Text
')
+ })
+ })
+
+ it('the button should make the selected text bold', () => {
+ cy.get('button:first')
+ .click()
+
+ cy.get('.ProseMirror')
+ .find('sub')
+ .should('contain', 'Example Text')
+ })
+
+ it('the button should toggle the selected text bold', () => {
+ cy.get('button:first').click()
+ cy.get('.ProseMirror').type('{selectall}')
+ cy.get('button:first').click()
+ cy.get('.ProseMirror sub').should('not.exist')
+ })
+})
diff --git a/docs/src/demos/Marks/Subscript/index.vue b/docs/src/demos/Marks/Subscript/index.vue
new file mode 100644
index 00000000..74c19056
--- /dev/null
+++ b/docs/src/demos/Marks/Subscript/index.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/demos/Marks/Superscript/index.spec.js b/docs/src/demos/Marks/Superscript/index.spec.js
new file mode 100644
index 00000000..9c642cc4
--- /dev/null
+++ b/docs/src/demos/Marks/Superscript/index.spec.js
@@ -0,0 +1,42 @@
+context('/demos/Marks/Superscript', () => {
+ before(() => {
+ cy.visit('/demos/Marks/Superscript')
+ })
+
+ beforeEach(() => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ cy.get('.ProseMirror').type('{selectall}')
+ })
+ })
+
+ it('should transform inline style to sup tags', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ expect(editor.getHTML()).to.eq('Example Text
')
+ })
+ })
+
+ it('sould omit inline style with a different vertical align', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text
')
+ expect(editor.getHTML()).to.eq('Example Text
')
+ })
+ })
+
+ it('the button should make the selected text bold', () => {
+ cy.get('button:first')
+ .click()
+
+ cy.get('.ProseMirror')
+ .find('sup')
+ .should('contain', 'Example Text')
+ })
+
+ it('the button should toggle the selected text bold', () => {
+ cy.get('button:first').click()
+ cy.get('.ProseMirror').type('{selectall}')
+ cy.get('button:first').click()
+ cy.get('.ProseMirror sup').should('not.exist')
+ })
+})
diff --git a/docs/src/demos/Marks/Superscript/index.vue b/docs/src/demos/Marks/Superscript/index.vue
new file mode 100644
index 00000000..dbea51ce
--- /dev/null
+++ b/docs/src/demos/Marks/Superscript/index.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/docPages/api/marks.md b/docs/src/docPages/api/marks.md
index 9ff4dc1a..48094aee 100644
--- a/docs/src/docPages/api/marks.md
+++ b/docs/src/docPages/api/marks.md
@@ -6,13 +6,15 @@
One or multiple marks can be applied to [nodes](/api/nodes), for example to add inline formatting like bold and italic, or other additional information.
## List of supported marks
-| Title | Default Extension | Source Code |
-| ---------------------------------- | ----------------- | -------------------------------------------------------------------------------------------- |
-| [Bold](/api/marks/bold) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-bold/) |
-| [Code](/api/marks/code) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-code/) |
-| [Highlight](/api/marks/highlight) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-highlight/) |
-| [Italic](/api/marks/italic) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-italic/) |
-| [Link](/api/marks/link) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-link/) |
-| [Strike](/api/marks/strike) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-strike/) |
-| [TextStyle](/api/marks/text-style) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-text-style/) |
-| [Underline](/api/marks/underline) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-underline/) |
+| Title | Default Extension | Source Code |
+| ------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------- |
+| [Bold](/api/marks/bold) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-bold/) |
+| [Code](/api/marks/code) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-code/) |
+| [Highlight](/api/marks/highlight) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-highlight/) |
+| [Italic](/api/marks/italic) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-italic/) |
+| [Link](/api/marks/link) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-link/) |
+| [Strike](/api/marks/strike) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-strike/) |
+| [Subscript](/api/marks/subscript) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-subscript/) |
+| [Superscript](/api/marks/superscript) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-superscript/) |
+| [TextStyle](/api/marks/text-style) | Yes | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-text-style/) |
+| [Underline](/api/marks/underline) | – | [GitHub](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-underline/) |
diff --git a/docs/src/docPages/api/marks/subscript.md b/docs/src/docPages/api/marks/subscript.md
new file mode 100644
index 00000000..64778343
--- /dev/null
+++ b/docs/src/docPages/api/marks/subscript.md
@@ -0,0 +1,32 @@
+# Subscript
+[](https://www.npmjs.com/package/@tiptap/extension-subscript)
+[](https://npmcharts.com/compare/@tiptap/extension-subscript?minimal=true)
+
+Use this extension to render text in subscript. If you pass `` or text with `vertical-align: sub` as inline style in the editor’s initial content, both will be normalized to a `` HTML tag.
+
+## Installation
+```bash
+# with npm
+npm install @tiptap/extension-subscript
+
+# with Yarn
+yarn add @tiptap/extension-subscript
+```
+
+## Settings
+| Option | Type | Default | Description |
+| -------------- | -------- | ------- | --------------------------------------------------------------------- |
+| HTMLAttributes | `Object` | `{}` | Custom HTML attributes that should be added to the rendered HTML tag. |
+
+## Commands
+| Command | Parameters | Description |
+| --------------- | ---------- | ------------------------- |
+| setSubscript | — | Mark text as subscript. |
+| toggleSubscript | — | Toggle subscript mark. |
+| unsetSubscript | — | Remove subscript mark. |
+
+## Source code
+[packages/extension-subscript/](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-subscript/)
+
+## Usage
+
diff --git a/docs/src/docPages/api/marks/superscript.md b/docs/src/docPages/api/marks/superscript.md
new file mode 100644
index 00000000..5a0a9c53
--- /dev/null
+++ b/docs/src/docPages/api/marks/superscript.md
@@ -0,0 +1,32 @@
+# Superscript
+[](https://www.npmjs.com/package/@tiptap/extension-superscript)
+[](https://npmcharts.com/compare/@tiptap/extension-superscript?minimal=true)
+
+Use this extension to render text in superscript. If you pass `` or text with `vertical-align: super` as inline style in the editor’s initial content, both will be normalized to a `` HTML tag.
+
+## Installation
+```bash
+# with npm
+npm install @tiptap/extension-superscript
+
+# with Yarn
+yarn add @tiptap/extension-superscript
+```
+
+## Settings
+| Option | Type | Default | Description |
+| -------------- | -------- | ------- | --------------------------------------------------------------------- |
+| HTMLAttributes | `Object` | `{}` | Custom HTML attributes that should be added to the rendered HTML tag. |
+
+## Commands
+| Command | Parameters | Description |
+| ----------------- | ---------- | ------------------------- |
+| setSuperscript | — | Mark text as superscript. |
+| toggleSuperscript | — | Toggle superscript mark. |
+| unsetSuperscript | — | Remove superscript mark. |
+
+## Source code
+[packages/extension-superscript/](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-superscript/)
+
+## Usage
+
diff --git a/docs/src/links.yaml b/docs/src/links.yaml
index 83f1ffdb..8808035e 100644
--- a/docs/src/links.yaml
+++ b/docs/src/links.yaml
@@ -320,6 +320,12 @@
link: /api/marks/link
- title: Strike
link: /api/marks/strike
+ - title: Subscript
+ link: /api/marks/subscript
+ type: new
+ - title: Superscript
+ link: /api/marks/superscript
+ type: new
- title: TextStyle
link: /api/marks/text-style
- title: Underline
diff --git a/packages/extension-subscript/README.md b/packages/extension-subscript/README.md
new file mode 100644
index 00000000..c231aebc
--- /dev/null
+++ b/packages/extension-subscript/README.md
@@ -0,0 +1,14 @@
+# @tiptap/extension-superscript
+[](https://www.npmjs.com/package/@tiptap/extension-superscript)
+[](https://npmcharts.com/compare/tiptap?minimal=true)
+[](https://www.npmjs.com/package/@tiptap/extension-superscript)
+[](https://github.com/sponsors/ueberdosis)
+
+## Introduction
+tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
+
+## Official Documentation
+Documentation can be found on the [tiptap website](https://tiptap.dev).
+
+## License
+tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md).
diff --git a/packages/extension-subscript/package.json b/packages/extension-subscript/package.json
new file mode 100644
index 00000000..f0840062
--- /dev/null
+++ b/packages/extension-subscript/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "@tiptap/extension-subscript",
+ "description": "subscript extension for tiptap",
+ "version": "2.0.0-beta.1",
+ "homepage": "https://tiptap.dev",
+ "keywords": [
+ "tiptap",
+ "tiptap extension"
+ ],
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/ueberdosis"
+ },
+ "main": "dist/tiptap-extension-subscript.cjs.js",
+ "umd": "dist/tiptap-extension-subscript.umd.js",
+ "module": "dist/tiptap-extension-subscript.esm.js",
+ "types": "dist/packages/extension-subscript/src/index.d.ts",
+ "files": [
+ "src",
+ "dist"
+ ],
+ "peerDependencies": {
+ "@tiptap/core": "^2.0.0-beta.1"
+ }
+}
diff --git a/packages/extension-subscript/src/index.ts b/packages/extension-subscript/src/index.ts
new file mode 100644
index 00000000..f1056848
--- /dev/null
+++ b/packages/extension-subscript/src/index.ts
@@ -0,0 +1,5 @@
+import { Subscript } from './subscript'
+
+export * from './subscript'
+
+export default Subscript
diff --git a/packages/extension-subscript/src/subscript.ts b/packages/extension-subscript/src/subscript.ts
new file mode 100644
index 00000000..06636207
--- /dev/null
+++ b/packages/extension-subscript/src/subscript.ts
@@ -0,0 +1,69 @@
+import { Command, Mark, mergeAttributes } from '@tiptap/core'
+
+export interface SubscriptExtensionOptions {
+ HTMLAttributes: Object,
+}
+
+declare module '@tiptap/core' {
+ interface Commands {
+ subscript: {
+ /**
+ * Set a subscript mark
+ */
+ setSubscript: () => Command,
+ /**
+ * Toggle a subscript mark
+ */
+ toggleSubscript: () => Command,
+ /**
+ * Unset a subscript mark
+ */
+ unsetSubscript: () => Command,
+ }
+ }
+}
+
+export const Subscript = Mark.create({
+ name: 'subscript',
+
+ defaultOptions: {
+ HTMLAttributes: {},
+ },
+
+ parseHTML() {
+ return [
+ {
+ tag: 'sub',
+ },
+ {
+ style: 'vertical-align',
+ getAttrs(value) {
+ // Don’t match this rule if the vertical align isn’t sub.
+ if (value !== 'sub') {
+ return false
+ }
+
+ // If it falls through we’ll match, and this mark will be applied.
+ },
+ },
+ ]
+ },
+
+ renderHTML({ HTMLAttributes }) {
+ return ['sub', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
+ },
+
+ addCommands() {
+ return {
+ setSubscript: () => ({ commands }) => {
+ return commands.setMark('subscript')
+ },
+ toggleSubscript: () => ({ commands }) => {
+ return commands.toggleMark('subscript')
+ },
+ unsetSubscript: () => ({ commands }) => {
+ return commands.unsetMark('subscript')
+ },
+ }
+ },
+})
diff --git a/packages/extension-superscript/README.md b/packages/extension-superscript/README.md
new file mode 100644
index 00000000..c231aebc
--- /dev/null
+++ b/packages/extension-superscript/README.md
@@ -0,0 +1,14 @@
+# @tiptap/extension-superscript
+[](https://www.npmjs.com/package/@tiptap/extension-superscript)
+[](https://npmcharts.com/compare/tiptap?minimal=true)
+[](https://www.npmjs.com/package/@tiptap/extension-superscript)
+[](https://github.com/sponsors/ueberdosis)
+
+## Introduction
+tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
+
+## Official Documentation
+Documentation can be found on the [tiptap website](https://tiptap.dev).
+
+## License
+tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md).
diff --git a/packages/extension-superscript/package.json b/packages/extension-superscript/package.json
new file mode 100644
index 00000000..e3a1fd2b
--- /dev/null
+++ b/packages/extension-superscript/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "@tiptap/extension-superscript",
+ "description": "superscript extension for tiptap",
+ "version": "2.0.0-beta.1",
+ "homepage": "https://tiptap.dev",
+ "keywords": [
+ "tiptap",
+ "tiptap extension"
+ ],
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/ueberdosis"
+ },
+ "main": "dist/tiptap-extension-superscript.cjs.js",
+ "umd": "dist/tiptap-extension-superscript.umd.js",
+ "module": "dist/tiptap-extension-superscript.esm.js",
+ "types": "dist/packages/extension-superscript/src/index.d.ts",
+ "files": [
+ "src",
+ "dist"
+ ],
+ "peerDependencies": {
+ "@tiptap/core": "^2.0.0-beta.1"
+ }
+}
diff --git a/packages/extension-superscript/src/index.ts b/packages/extension-superscript/src/index.ts
new file mode 100644
index 00000000..23c2140e
--- /dev/null
+++ b/packages/extension-superscript/src/index.ts
@@ -0,0 +1,5 @@
+import { Superscript } from './superscript'
+
+export * from './superscript'
+
+export default Superscript
diff --git a/packages/extension-superscript/src/superscript.ts b/packages/extension-superscript/src/superscript.ts
new file mode 100644
index 00000000..26a348aa
--- /dev/null
+++ b/packages/extension-superscript/src/superscript.ts
@@ -0,0 +1,69 @@
+import { Command, Mark, mergeAttributes } from '@tiptap/core'
+
+export interface SuperscriptExtensionOptions {
+ HTMLAttributes: Object,
+}
+
+declare module '@tiptap/core' {
+ interface Commands {
+ superscript: {
+ /**
+ * Set a superscript mark
+ */
+ setSuperscript: () => Command,
+ /**
+ * Toggle a superscript mark
+ */
+ toggleSuperscript: () => Command,
+ /**
+ * Unset a superscript mark
+ */
+ unsetSuperscript: () => Command,
+ }
+ }
+}
+
+export const Superscript = Mark.create({
+ name: 'superscript',
+
+ defaultOptions: {
+ HTMLAttributes: {},
+ },
+
+ parseHTML() {
+ return [
+ {
+ tag: 'sup',
+ },
+ {
+ style: 'vertical-align',
+ getAttrs(value) {
+ // Don’t match this rule if the vertical align isn’t super.
+ if (value !== 'super') {
+ return false
+ }
+
+ // If it falls through we’ll match, and this mark will be applied.
+ },
+ },
+ ]
+ },
+
+ renderHTML({ HTMLAttributes }) {
+ return ['sup', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
+ },
+
+ addCommands() {
+ return {
+ setSuperscript: () => ({ commands }) => {
+ return commands.setMark('superscript')
+ },
+ toggleSuperscript: () => ({ commands }) => {
+ return commands.toggleMark('superscript')
+ },
+ unsetSuperscript: () => ({ commands }) => {
+ return commands.unsetMark('superscript')
+ },
+ }
+ },
+})