README.md

tiptap

Why I built tiptap

I was looking for a text editor for Vue.js and found some solutions that didn't really satisfy me. The editor should be easy to extend and not based on old dependencies such as jQuery. For React there is already a great editor called Slate.js, which impresses with its modularity. I came across Prosemirror and decided to build on it. Prosemirror is a toolkit for building rich-text editors that are already in use at many well-known companies such as Atlassian or New York Times.

What does renderless mean?

With renderless components you'll have (almost) full control over markup and styling. I don't want to tell you what a menu should look like or where it should be rendered in the DOM. That's all up to you. There is also a good article about renderless components by Adam Wathan.

How is the data stored under the hood?

You can save your data as a raw HTML string or can get a JSON-serializable representation of your document. And of course, you can pass these two types back to the editor.

Create a Node

Let's take a look at a real example. This is basically how the default blockquote node from tiptap-extensions looks like.

import { Node } from'tiptap'import { wrappingInputRule, setBlockType, toggleWrap } from'tiptap-commands'exportdefaultclassBlockquoteNodeextendsNode {
// choose a unique namegetname() {
return'blockquote'
}
// the prosemirror schema object// take a look at https://prosemirror.net/docs/guide/#schema for a detailed explanationgetschema() {
return {
content:'block+',
group:'block',
defining:true,
draggable:false,
// define how the editor will detect your node from pasted HTML// every blockquote tag will be converted to this blockquote node
parseDOM: [
{ tag:'blockquote' },
],
// this is how this node will be rendered// in this case a blockquote tag with a class called `awesome-blockquote` will be rendered// the '0' stands for its text content insidetoDOM: () => ['blockquote', { class:'awesome-blockquote' }, 0],
}
}
// this command will be called from menus to add a blockquote// `type` is the prosemirror schema object for this blockquote// `schema` is a collection of all registered nodes and markscommands({ type, schema }) {
return () =>toggleWrap(type)
}
// here you can register some shortcuts// in this case you can create a blockquote with `ctrl` + `>`keys({ type }) {
return {
'Ctrl->':toggleWrap(type),
}
}
// a blockquote will be created when you are on a new line and type `>` followed by a spaceinputRules({ type }) {
return [
wrappingInputRule(/^\s*>\s$/, type),
]
}
}

Create a Node as a Vue Component

The real power of the nodes comes in combination with Vue components. Let us build an iframe node, where you can change its URL (this can also be found in our examples).