Mark Button

Available for free

A fully accessible mark button for Tiptap editors. Easily toggle text formatting marks like bold, italic, strikethrough, and more with keyboard shortcut support and flexible customization options.

Installation

Add the component via the Tiptap CLI:

npx @tiptap/cli@latest add mark-button

Components

<MarkButton />

A prebuilt React component that toggles mark formatting for a specific mark type.

Usage

import { useEditor, EditorContent, EditorContext } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { Underline } from '@tiptap/extension-underline'
import { Superscript } from '@tiptap/extension-superscript'
import { Subscript } from '@tiptap/extension-subscript'
import { MarkButton } from '@/components/tiptap-ui/mark-button'

import '@/components/tiptap-node/code-block-node/code-block-node.scss'
import '@/components/tiptap-node/paragraph-node/paragraph-node.scss'

export default function MyEditor() {
  const editor = useEditor({
    immediatelyRender: false,
    extensions: [StarterKit, Underline, Superscript, Subscript],
    content: `
        <p>
            <strong>Bold</strong> for emphasis with <code>**</code> or <code>⌘+B</code> or the <code>B</code> button.
        </p>
        <p>
            <em>Italic</em> for subtle nuances with <code>*</code> or <code>⌘+I</code> or the <code>I</code> button.
        </p>
        <p>
            <s>Strikethrough</s> to show revisions with <code>~~</code> or the <code>~~S~~</code> button.
        </p>
        <p>
            <code>Code</code> for code snippets with <code>:</code> or <code>⌘+⇧+C</code> or the <code>C</code> button.
        </p>
        <p>
            <u>Underline</u> for emphasis with <code>⌘+U</code> or the <code>U</code> button.
        </p>
        <p>
            <sup>Superscript</sup> for footnotes with <code>⌘+.</code> or the <code>.</code> button.
        </p>
        <p>
            <sub>Subscript</sub> for chemical formulas with <code>⌘+,</code> or the <code>,</code> button.
        </p>
        `,
  })

  return (
    <EditorContext.Provider value={{ editor }}>
      <MarkButton
        editor={editor}
        type="bold"
        text="Bold"
        hideWhenUnavailable={true}
        showShortcut={true}
        onToggled={() => console.log('Mark toggled!')}
      />
      <MarkButton type="italic" />
      <MarkButton type="strike" />
      <MarkButton type="code" />
      <MarkButton type="underline" />
      <MarkButton type="superscript" />
      <MarkButton type="subscript" />

      <EditorContent editor={editor} role="presentation" />
    </EditorContext.Provider>
  )
}

Props

NameTypeDefaultDescription
editorEditor | nullundefinedThe Tiptap editor instance
typeMarkrequiredThe type of mark ("bold", "italic", "strike", etc.)
textstringundefinedOptional text label for the button
hideWhenUnavailablebooleanfalseHides the button when mark toggle is not available
onToggled() => voidundefinedCallback fired after a successful mark toggle
showShortcutbooleanfalseShows a keyboard shortcut badge (if available)

Hooks

useMark()

A custom hook to build your own mark button with full control over rendering and behavior.

Usage

import { useMark } from '@/components/tiptap-ui/mark-button'
import { parseShortcutKeys } from '@/lib/tiptap-utils'
import { Badge } from '@/components/tiptap-ui-primitive/badge'

function MyMarkButton() {
  const { isVisible, isActive, canToggle, handleMark, label, shortcutKeys, Icon } = useMark({
    editor: myEditor,
    type: 'bold',
    hideWhenUnavailable: true,
    onToggled: () => console.log('Mark toggled!'),
  })

  if (!isVisible) return null

  return (
    <button
      onClick={handleMark}
      disabled={!canToggle}
      aria-label={label}
      aria-pressed={isActive}
      title={label}
    >
      <Icon />
      {label}
      {shortcutKeys && <Badge>{parseShortcutKeys({ shortcutKeys })}</Badge>}
    </button>
  )
}

Props

NameTypeDefaultDescription
editorEditor | nullundefinedThe Tiptap editor instance
typeMarkrequiredThe type of mark to toggle
hideWhenUnavailablebooleanfalseHides the button if mark toggle is not available
onToggled() => voidundefinedCallback fired after a successful mark toggle

Return Values

NameTypeDescription
isVisiblebooleanWhether the button should be rendered
isActivebooleanIf the specific mark type is currently active
canTogglebooleanIf the mark toggle is currently allowed
handleMark() => booleanFunction to toggle mark formatting, returns success
labelstringFormatted display name (e.g., "Bold", "Italic")
shortcutKeysstringKeyboard shortcut for the specific mark type
IconReact.FCIcon component for the mark button

Utilities

canToggleMark(editor, type)

Checks if a specific mark type can be toggled in the current editor state.

Parameters:

  • editor: Editor | null - The Tiptap editor instance
  • type: Mark - The mark type to check

Returns: boolean - Whether the mark can be toggled

import { canToggleMark } from '@/components/tiptap-ui/mark-button'

const canToggle = canToggleMark(editor, 'bold') // Check if bold can be toggled

toggleMark(editor, type)

Programmatically toggles mark formatting for the specified type.

Parameters:

  • editor: Editor | null - The Tiptap editor instance
  • type: Mark - The mark type to toggle

Returns: boolean - Whether the toggle was successful

import { toggleMark } from '@/components/tiptap-ui/mark-button'

const success = toggleMark(editor, 'italic')
if (success) {
  console.log('Italic mark toggled successfully!')
}

isMarkActive(editor, type)

Checks if a specific mark type is currently active.

Parameters:

  • editor: Editor | null - The Tiptap editor instance
  • type: Mark - The mark type to check

Returns: boolean - Whether the mark is active

import { isMarkActive } from '@/components/tiptap-ui/mark-button'

const active = isMarkActive(editor, 'underline')

getFormattedMarkName(type)

Gets the formatted display name for a mark type.

Parameters:

  • type: Mark - The mark type

Returns: string - The formatted name (e.g., "Bold", "Italic")

import { getFormattedMarkName } from '@/components/tiptap-ui/mark-button'

const name = getFormattedMarkName('bold') // Returns "Bold"
const name2 = getFormattedMarkName('superscript') // Returns "Superscript"

shouldShowButton(props)

Determines if the mark button should be shown based on editor state and configuration.

Parameters:

  • props: object
    • editor: Editor | null - The Tiptap editor instance
    • type: Mark - The mark type
    • hideWhenUnavailable: boolean - Whether to hide when unavailable

Returns: boolean - Whether the button should be shown

import { shouldShowButton } from '@/components/tiptap-ui/mark-button'

const shouldShow = shouldShowButton({
  editor,
  type: 'bold',
  hideWhenUnavailable: true,
})

Keyboard Shortcuts

Each mark type has its own keyboard shortcut:

  • Cmd/Ctrl + B: Toggle bold
  • Cmd/Ctrl + I: Toggle italic
  • Cmd/Ctrl + U: Toggle underline
  • Cmd/Ctrl + Shift + S: Toggle strikethrough
  • Cmd/Ctrl + E: Toggle code
  • Cmd/Ctrl + .: Toggle superscript
  • Cmd/Ctrl + ,: Toggle subscript

The shortcuts are automatically registered when using either the <MarkButton /> component or the useMark() hook.

Requirements

Dependencies

  • @tiptap/react - Core Tiptap React integration
  • @tiptap/starter-kit - Basic Tiptap extensions including mark support
  • @tiptap/extension-underline - Underline mark extension
  • @tiptap/extension-superscript - Superscript mark extension
  • @tiptap/extension-subscript - Subscript mark extension
  • react-hotkeys-hook - Keyboard shortcut management

Referenced Components

  • use-tiptap-editor (hook)
  • button (primitive)
  • badge (primitive)
  • tiptap-utils (lib)
  • bold-icon (icon)
  • italic-icon (icon)
  • underline-icon (icon)
  • strike-icon (icon)
  • code-2-icon (icon)
  • superscript-icon (icon)
  • subscript-icon (icon)