Mark API
The power of Tiptap lies in its flexibility. You can create your own extensions from scratch and build a unique editor experience tailored to your needs.
Creating a mark
Marks are used to add inline formatting to text in Tiptap. Common examples include bold, italic, and underline formatting.
They extend all of the options and methods from the Extension API and add a few more specific to marks.
Let's add a simple mark extension to see how it works.
import { Mark } from '@tiptap/core'
const HighlightMark = Mark.create({
name: 'highlight',
addOptions() {
return {
HTMLAttributes: {},
}
},
parseHTML() {
return [
{
tag: 'mark',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['mark', HTMLAttributes, 0]
},
})You can also use a callback function to create a mark. This is useful if you want to encapsulate the logic of your extension, for example when you want to define event handlers or other custom logic.
import { Mark } from '@tiptap/core'
const CustomMark = Mark.create(() => {
// Define variables or functions to use inside your extension
const customVariable = 'foo'
function onCreate() {}
function onUpdate() {}
return {
name: 'customMark',
onCreate,
onUpdate,
// Your code goes here.
}
})This code creates a new mark extension named HighlightMark. It adds an addOptions method to define the mark's options, which are configurable by the user. It also adds parseHTML and renderHTML methods to define how the mark is parsed and rendered as HTML.
It is installed to the editor just like any other extension by adding it to the extensions array.
import { Editor } from '@tiptap/core'
new Editor({
extensions: [HighlightMark],
})
// Or if using React or Vue
const editor = useEditor({
extensions: [HighlightMark],
})Now let's take a closer look at the options and methods available for marks.
Mark options
When creating a mark extension, you can define options that are configurable by the user. These options can be used to customize the behavior or appearance of the mark.
parseHTML
The parseHTML method is used to define how the mark is parsed from HTML. It should return an array of objects representing the mark's attributes.
Maps to the parseDOM attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
parseHTML() {
return [
{
tag: 'span',
getAttrs: (node) => {
return {
class: node.getAttribute('class'),
}
},
},
]
},
})This will be used during paste events to parse the HTML content into a mark.
renderHTML
The renderHTML method is used to define how the mark is rendered as HTML. It should return an array representing the mark's HTML representation.
Maps to the toDOM attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
renderHTML({ HTMLAttributes }) {
return ['span', HTMLAttributes, 0]
},
})This will be used during copy events to render the mark as HTML. For more details, see the extend existing extensions guide.
addAttributes
The addAttributes method is used to define custom attributes for the mark. It should return an object with the attribute names and their default values.
Maps to the attrs attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
addAttributes() {
return {
customAttribute: {
default: 'value',
parseHTML: (element) => element.getAttribute('data-custom-attribute'),
},
}
},
})For more details, see the extend existing extensions guide.
keepOnSplit
By default, when a node is split, marks are removed from the content. You can set keepOnSplit to true to keep the mark on the new node.
const CustomMark = Mark.create({
name: 'customMark',
keepOnSplit: true,
})inclusive
By default, marks are not inclusive, meaning they cannot be applied to the start or end of a node. You can set inclusive to true to allow the mark to be applied to the start or end of a node.
Maps to the inclusive attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
inclusive: true,
})excludes
By default, marks do not exclude other marks. You can define a list of marks that should be excluded when this mark is applied.
Maps to the excludes attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
excludes: ['bold', 'italic'],
})exitable
By default, marks are not exitable, meaning they cannot be removed by pressing backspace at the start of the mark. You can set exitable to true to allow the mark to be removed in this way.
Maps to the exitable attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
exitable: true,
})group
By default, marks are not grouped, meaning they are applied individually. You can define a group for the mark to ensure that only one mark from the group can be applied at a time.
Maps to the group attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
group: 'textStyle',
})spanning
By default, marks do not span multiple nodes. You can set spanning to true to allow the mark to span multiple nodes.
Maps to the spanning attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
spanning: true,
})code
By default, marks are not treated as code marks. You can set code to true to treat the mark as a code mark.
Maps to the code attribute in the ProseMirror schema.
const CustomMark = Mark.create({
name: 'customMark',
code: true,
})