mcpField
U
umbraco-tiptap-toolbar-extension

umbraco-tiptap-toolbar-extension

github.com/umbracoDevelopment27374 installsUpdated 6w ago
Repository

About umbraco-tiptap-toolbar-extension

A skill for building toolbar extensions for the Umbraco Tiptap Rich Text Editor. It covers several control types and guides developers through documentation review, manifest and API creation, and testing.

Key features

  1. 01Button, menu, and style controls
  2. 02Color-picker button guidance
  3. 03Manifest and API examples
  4. 04Active and disabled state guidance
  5. 05Documentation-first workflow

Use cases

  1. 01Add a formatting toggle button
  2. 02Offer heading or style options in a menu
  3. 03Let editors choose text colors
  4. 04Open a modal from a toolbar button

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-tiptap-toolbar-extension

After installing, type/umbraco-tiptap-toolbar-extensionin Claude Code to confirm it loaded.

Details

From the project README

Umbraco Tiptap Toolbar Extension

What is it?

A Tiptap Toolbar Extension adds buttons or controls to the Rich Text Editor's toolbar. It provides an execute method that runs when clicked, and can indicate active/disabled states. Several "kinds" are available: button (simple toggle), colorPickerButton (color selection), menu (dropdown menu), and styleMenu (style selection dropdown).

Documentation

Always fetch the latest docs before implementing:

Related Skills

  • Tiptap Extension: For adding editor functionality

    • Reference skill: umbraco-tiptap-extension
  • Modals: When toolbar buttons open modal dialogs

    • Reference skill: umbraco-modals

Workflow

  1. Fetch docs - Use WebFetch on the URLs above
  2. Ask questions - Button, menu, or color picker? What action to execute?
  3. Generate files - Create manifest + API class based on latest docs
  4. Explain - Show what was created and how to test

Minimal Examples

Button Kind Manifest (manifests.ts)
import type { ManifestTiptapToolbarExtensionButtonKind } from '@umbraco-cms/backoffice/extension-registry';

const manifest: ManifestTiptapToolbarExtensionButtonKind = {
  type: 'tiptapToolbarExtension',
  kind: 'button',
  alias: 'My.TiptapToolbar.Bold',
  name: 'Bold Toolbar Button',
  api: () => import('./bold.tiptap-toolbar-api.js'),
  forExtensions: ['Umb.Tiptap.Bold'], // Links to the tiptap extension
  meta: {
    alias: 'bold',
    icon: 'icon-bold',
    label: 'Bold',
  },
};

export const manifests = [manifest];
Button API (bold.tiptap-toolbar-api.ts)
import { UmbTiptapToolbarElementApiBase } from '@umbraco-cms/backoffice/tiptap';
import type { Editor } from '@tiptap/core';

export default class BoldToolbarApi extends UmbTiptapToolbarElementApiBase {
  execute(editor?: Editor) {
    editor?.chain().focus().toggleBold().run();
  }
}
Button with Custom Active/Disabled State
import { UmbTiptapToolbarElementApiBase } from '@umbraco-cms/backoffice/tiptap';
import type { Editor } from '@tiptap/core';

export default class CustomToolbarApi extends UmbTiptapToolbarElementApiBase {
  execute(editor?: Editor) {
    editor?.chain().focus().toggleHighlight().run();
  }

  // Override to customize active state detection
  isActive(editor?: Editor): boolean {
    return editor?.isActive('highlight') ?? false;
  }

  // Override to customize disabled state
  isDisabled(editor?: Editor): boolean {
    return !editor?.can().toggleHighlight() ?? true;
  }
}
Menu Kind Manifest
import type { ManifestTiptapToolbarExtensionMenuKind } from '@umbraco-cms/backoffice/extension-registry';

const manifest: ManifestTiptapToolbarExtensionMenuKind = {
  type: 'tiptapToolbarExtension',
  kind: 'menu',
  alias: 'My.TiptapToolbar.Headings',
  name: 'Headings Menu',
  api: () => import('./headings.tiptap-toolbar-api.js'),
  forExtensions: ['Umb.Tiptap.Heading'],
  meta: {
    alias: 'headings',
    icon: 'icon-heading',
    label: 'Headings',
    look: 'text', // 'icon' or 'text'
  },
  items: [
    { label: 'Heading 1', data: { level: 1 } },
    { label: 'Heading 2', data: { level: 2 } },
    { label: 'Heading 3', data: { level: 3 } },
    { label: 'Paragraph', data: { level: 0 } },
  ],
};
Menu API
import { UmbTiptapToolbarElementApiBase } from '@umbraco-cms/backoffice/tiptap';
import type { Editor } from '@tiptap/core';

export default class HeadingsToolbarApi extends UmbTiptapToolbarElementApiBase {
  execute(editor?: Editor, level?: number) {
    if (level === 0) {
      editor?.chain().focus().setParagraph().run();
    } else {
      editor?.chain().focus().toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run();
    }
  }

  isActive(editor?: Editor, level?: number): boolean {
    if (level === 0) {
      return editor?.isActive('paragraph') ?? false;
    }
    return editor?.isActive('heading', { level }) ?? false;
  }
}
Style Menu Kind
import type { ManifestTiptapToolbarExtensionStyleMenuKind } from '@umbraco-cms/backoffice/extension-registry';

const manifest: ManifestTiptapToolbarExtensionStyleMenuKind = {
  type: 'tiptapToolbarExtension',
  kind: 'styleMenu',
  alias: 'My.TiptapToolbar.Styles',
  name: 'Style Menu',
  api: () => import('./styles.tiptap-toolbar-api.js'),
  meta: {
    alias: 'styles',
    icon: 'icon-palette',
    label: 'Styles',
  },
  items: [
    {
      label: 'Lead Paragraph',
      data: { class: 'lead' },
      appearance: { style: 'font-size: 1.2em' },
    },
    {
      label: 'Small Text',
      data: { class: 'small' },
      appearance: { style: 'font-size: 0.85em' },
    },
    {
      label: 'Highlight Box',
      data: { class: 'highlight-box' },
    },
  ],
};
Color Picker Button Kind
import type { ManifestTiptapToolbarExtensionColorPickerButtonKind } from '@umbraco-cms/backoffice/extension-registry';

const manifest: ManifestTiptapToolbarExtensionColorPickerButtonKind = {
  type: 'tiptapToolbarExtension',
  kind: 'colorPickerButton',
  alias: 'My.TiptapToolbar.TextColor',
  name: 'Text Color',
  api: () => import('./text-color.tiptap-toolbar-api.js'),
  meta: {
    alias: 'textColor',
    icon: 'icon-palette',
    label: 'Text Color',
  },
};
Toolbar Button Opening Modal
import { UmbTiptapToolbarElementApiBase } from '@umbraco-cms/backoffice/tiptap';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { Editor } from '@tiptap/core';

export default class LinkToolbarApi extends UmbTiptapToolbarElementApiBase {
  async execute(editor?: Editor) {
    const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);

    const modal = modalManager.open(this, MY_LINK_MODAL, {
      data: {
        currentHref: editor?.getAttributes('link').href,
      },
    });

    const result = await modal.onSubmit();
    if (result?.href) {
      editor?.chain().focus().setLink({ href: result.href }).run();
    }
  }
}

Toolbar Extension Kinds

KindUse Case
buttonSimple toggle button
colorPickerButtonColor selection
menuDropdown with options
styleMenuStyle/class selection

Meta Properties

PropertyDescription
aliasUsed for isActive detection
iconToolbar button icon
labelTooltip text
look(menu only) 'icon' or 'text'

That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.

Comments

Markdown supported