> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ueberdosis/tiptap/llms.txt
> Use this file to discover all available pages before exploring further.

# Mark

> The Mark class is used to create custom mark types in Tiptap.

## Creating a Mark

Use the static `create` method to define a new mark.

```typescript theme={null}
import { Mark } from '@tiptap/core'

const MyMark = Mark.create<Options, Storage>({
  name: 'myMark',
  // ... configuration
})
```

<ParamField path="config" type="Partial<MarkConfig<Options, Storage>> | (() => Partial<MarkConfig<Options, Storage>>)">
  The mark configuration object or a function that returns a configuration object.
</ParamField>

## Configuration Options

Marks inherit all configuration options from [Extension](/api/extension#configuration-options), plus the following:

### inclusive

Whether the mark should be active when the cursor is at the boundary.

```typescript theme={null}
inclusive?: boolean | ((this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['inclusive']
  editor?: Editor
}) => boolean)
```

<ParamField path="inclusive" type="boolean">
  If `true`, the mark is active when the cursor is at its start/end. If `false`, it requires the cursor to be inside.
</ParamField>

**Example**

```typescript theme={null}
inclusive: false // e.g., for link marks
```

### excludes

Define which other marks this mark excludes.

```typescript theme={null}
excludes?: string | ((this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['excludes']
  editor?: Editor
}) => string)
```

<ParamField path="excludes" type="string">
  Space-separated mark names, or `"_"` to exclude all other marks.
</ParamField>

**Example**

```typescript theme={null}
// Exclude all other marks
excludes: '_'

// Exclude specific marks
excludes: 'bold italic'

// Don't exclude any marks (default)
excludes: ''
```

### exitable

Whether the mark can be exited at the end.

```typescript theme={null}
exitable?: boolean | (() => boolean)
```

<ParamField path="exitable" type="boolean" default="false">
  If `true`, pressing right arrow at the end of the mark will move outside of it.
</ParamField>

**Example**

```typescript theme={null}
exitable: true
```

### group

Define the group(s) this mark belongs to.

```typescript theme={null}
group?: string | ((this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['group']
  editor?: Editor
}) => string)
```

<ParamField path="group" type="string">
  Space-separated group names.
</ParamField>

**Example**

```typescript theme={null}
group: 'formatting'
```

### spanning

Whether the mark spans across multiple nodes.

```typescript theme={null}
spanning?: boolean | ((this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['spanning']
  editor?: Editor
}) => boolean)
```

<ParamField path="spanning" type="boolean">
  If `false`, the mark is removed when split.
</ParamField>

### code

Whether the mark represents code.

```typescript theme={null}
code?: boolean | ((this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['code']
  editor?: Editor
}) => boolean)
```

<ParamField path="code" type="boolean" default="false">
  Indicates that this mark contains code.
</ParamField>

**Example**

```typescript theme={null}
code: true
```

### keepOnSplit

Whether to keep the mark after splitting a node.

```typescript theme={null}
keepOnSplit?: boolean | (() => boolean)
```

<ParamField path="keepOnSplit" type="boolean" default="true">
  If `true`, the mark continues after splitting a text block.
</ParamField>

**Example**

```typescript theme={null}
keepOnSplit: false
```

### parseHTML()

Define how to parse HTML into this mark.

```typescript theme={null}
parseHTML?(this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['parseHTML']
  editor?: Editor
}): ParseRule[]
```

**Example**

```typescript theme={null}
parseHTML() {
  return [
    { tag: 'strong' },
    { tag: 'b', getAttrs: node => (node as HTMLElement).style.fontWeight !== 'normal' && null },
    { style: 'font-weight', getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value as string) && null },
  ]
}
```

### renderHTML()

Define how to render the mark as HTML.

```typescript theme={null}
renderHTML?(this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['renderHTML']
  editor?: Editor
}, props: {
  mark: ProseMirrorMark
  HTMLAttributes: Record<string, any>
}): DOMOutputSpec
```

**Example**

```typescript theme={null}
renderHTML({ HTMLAttributes }) {
  return ['strong', HTMLAttributes, 0]
}

// With custom attributes
renderHTML({ mark, HTMLAttributes }) {
  return [
    'span',
    { ...HTMLAttributes, class: 'bold', 'data-weight': mark.attrs.weight },
    0, // 0 represents where content goes
  ]
}
```

### addAttributes()

Define attributes for the mark.

```typescript theme={null}
addAttributes?(this: {
  name: string
  options: Options
  storage: Storage
  parent: ParentConfig['addAttributes']
  editor?: Editor
}): Attributes | {}
```

**Example**

```typescript theme={null}
addAttributes() {
  return {
    href: {
      default: null,
      parseHTML: element => element.getAttribute('href'),
      renderHTML: attributes => {
        if (!attributes.href) return {}
        return { href: attributes.href }
      },
    },
    target: {
      default: '_blank',
      parseHTML: element => element.getAttribute('target'),
      renderHTML: attributes => {
        if (!attributes.target) return {}
        return { target: attributes.target, rel: 'noopener noreferrer' }
      },
    },
    class: {
      default: null,
      parseHTML: element => element.getAttribute('class'),
      renderHTML: attributes => {
        if (!attributes.class) return {}
        return { class: attributes.class }
      },
    },
  }
}
```

### addMarkView()

Define a custom mark view.

```typescript theme={null}
addMarkView?(this: {
  name: string
  options: Options
  storage: Storage
  editor: Editor
  type: MarkType
  parent: ParentConfig['addMarkView']
}): MarkViewRenderer
```

**Example**

```typescript theme={null}
addMarkView() {
  return ({ mark }) => {
    const span = document.createElement('span')
    span.classList.add('custom-mark')
    span.style.color = mark.attrs.color
    return span
  }
}
```

## Methods

### configure()

Create a configured version of the mark.

```typescript theme={null}
mark.configure(options?: Partial<Options>): Mark<Options, Storage>
```

<ParamField path="options" type="Partial<Options>">
  Options to override the default options.
</ParamField>

**Example**

```typescript theme={null}
import Link from '@tiptap/extension-link'

const editor = new Editor({
  extensions: [
    Link.configure({
      openOnClick: false,
      linkOnPaste: true,
    }),
  ],
})
```

### extend()

Extend the mark with additional configuration.

```typescript theme={null}
mark.extend<ExtendedOptions, ExtendedStorage, ExtendedConfig>(
  extendedConfig?: Partial<ExtendedConfig> | (() => Partial<ExtendedConfig>)
): Mark<ExtendedOptions, ExtendedStorage>
```

<ParamField path="extendedConfig" type="Partial<ExtendedConfig> | (() => Partial<ExtendedConfig>)">
  Additional configuration or a function that returns configuration.
</ParamField>

**Example**

```typescript theme={null}
import Bold from '@tiptap/extension-bold'

const CustomBold = Bold.extend({
  addAttributes() {
    return {
      ...this.parent?.(),
      weight: {
        default: 'bold',
        parseHTML: element => element.style.fontWeight,
        renderHTML: attributes => {
          return { style: `font-weight: ${attributes.weight}` }
        },
      },
    }
  },
})
```

## Complete Example

```typescript theme={null}
import { Mark, mergeAttributes } from '@tiptap/core'

interface HighlightOptions {
  multicolor: boolean
  HTMLAttributes: Record<string, any>
}

const Highlight = Mark.create<HighlightOptions>({
  name: 'highlight',

  addOptions() {
    return {
      multicolor: false,
      HTMLAttributes: {},
    }
  },

  addAttributes() {
    if (!this.options.multicolor) {
      return {}
    }

    return {
      color: {
        default: null,
        parseHTML: element => element.getAttribute('data-color') || element.style.backgroundColor,
        renderHTML: attributes => {
          if (!attributes.color) {
            return {}
          }

          return {
            'data-color': attributes.color,
            style: `background-color: ${attributes.color}; color: inherit`,
          }
        },
      },
    }
  },

  parseHTML() {
    return [
      {
        tag: 'mark',
      },
      {
        style: 'background-color',
        getAttrs: value => {
          // Don't match if the background color is the default one
          return value === 'transparent' ? false : null
        },
      },
    ]
  },

  renderHTML({ HTMLAttributes }) {
    return ['mark', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
  },

  addCommands() {
    return {
      setHighlight: attributes => ({ commands }) => {
        return commands.setMark(this.name, attributes)
      },
      toggleHighlight: attributes => ({ commands }) => {
        return commands.toggleMark(this.name, attributes)
      },
      unsetHighlight: () => ({ commands }) => {
        return commands.unsetMark(this.name)
      },
    }
  },

  addKeyboardShortcuts() {
    return {
      'Mod-Shift-h': () => this.editor.commands.toggleHighlight(),
    }
  },
})

// Usage
const editor = new Editor({
  extensions: [
    Highlight.configure({
      multicolor: true,
    }),
  ],
})

// Apply highlight
editor.commands.setHighlight({ color: '#ffc078' })

// Toggle highlight
editor.commands.toggleHighlight({ color: '#ffc078' })

// Remove highlight
editor.commands.unsetHighlight()
```
