Skip to main content

Creating a custom node

Custom extensions use EmailNode, which extends TipTap’s Node with one extra required method: renderToVueEmail(). Use parseHTML() to recognize pasted or imported HTML, renderHTML() to control how the node appears in the editor, and renderToVueEmail() to control how it is exported by composeVueEmail. renderToVueEmail() is a plain function that returns VNodes, built with h() from Vue. It receives the node’s content already rendered as children, which plain elements take as their children ([children]). Here’s a complete example of a custom “Callout” node that renders as a highlighted block:
callout.ts
Numbers in the styles of plain elements, like the div above, don’t get a px unit added, so write sizes as strings with their units. Vuemail components, like Section or Text, add px to numbers like React Email does. Pass the children of a Vuemail component as its default slot: h(Section, { style }, () => children).

Registering the extension

Add your custom extension to the extensions array alongside StarterKit:

Inserting custom nodes

Use the editor’s insertContent command to programmatically insert your custom node:
toolbar.vue

Complete example

Here’s the full editor setup with the custom Callout extension, a toolbar, and a bubble menu:
toolbar.vue
my-editor.vue

Wrapping existing TipTap extensions

Both EmailNode and EmailMark provide a .from() method that wraps an existing TipTap extension with email serialization support. This is useful when you want to reuse a community TipTap extension and add email export support without rewriting it.
For full API details on all methods (create, from, configure, extend), see the EmailNode and EmailMark reference pages.

Configure and extend

Both EmailNode and EmailMark support TipTap’s standard customization methods:

Examples

See custom extensions in action with a runnable example:

Custom Extensions

Custom Callout node with EmailNode.create, toolbar insertion, and bubble menu.