tiptap/docs/guide/node-views/js.md
Philipp Kühn 569aa15c4f Merge branch 'main' of https://github.com/ueberdosis/tiptap into docs/remove-gridsome
# Conflicts:
#	docs/experiments/collaboration-annotation.md
#	docs/experiments/global-drag-handle.md
2021-09-17 23:45:04 +02:00

124 lines
4.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
tableOfContents: true
---
# Node views with JavaScript
## Introduction
Using frameworks like Vue or React can feel too complex, if youre used to work without those two. Good news: You can use Vanilla JavaScript in your node views. There is just a little bit you need to know, but lets go through this one by one.
## Render a node view with JavaScript
Here is what you need to do to render a node view inside your editor:
1. [Create a node extension](/guide/custom-extensions)
2. Register a new node view with `addNodeView()`
3. Write your render function
4. [Configure tiptap to use your new node extension](/guide/configuration)
This is how your node extension could look like:
```js
import { Node } from '@tiptap/core'
import Component from './Component.vue'
export default Node.create({
// configuration …
addNodeView() {
return ({ editor, node, getPos, HTMLAttributes, decorations, extension }) => {
const dom = document.createElement('div')
dom.innerHTML = 'Hello, Im a node view!'
return {
dom,
}
}
},
})
```
Got it? Lets see it in action. Feel free to copy the below example to get started.
<tiptap-demo name="GuideNodeViews/JavaScript"></tiptap-demo>
That node view even interacts with the editor. Time to see how that is wired up.
## Access node attributes
The editor passes a few helpful things to your render function. One of them is the the `node` prop. This one enables you to access node attributes in your node view. Lets say you have [added an attribute](/guide/custom-extensions#attributes) named `count` to your node extension. You could access the attribute like this:
```js
addNodeView() {
return ({ node }) => {
console.log(node.attrs.count)
// …
}
}
```
## Update node attributes
You can even update node attributes from your node view, with the help of the `getPos` prop passed to your render function. Dispatch a new transaction with an object of the updated attributes:
```js
addNodeView() {
return ({ editor, node, getPos }) => {
const { view } = editor
// Create a button …
const button = document.createElement('button')
button.innerHTML = `This button has been clicked ${node.attrs.count} times.`
// … and when its clicked …
button.addEventListener('click', () => {
if (typeof getPos === 'function') {
// … dispatch a transaction, for the current position in the document …
view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, {
count: node.attrs.count + 1,
}))
// … and set the focus back to the editor.
editor.commands.focus()
}
})
// …
}
}
```
Does seem a little bit too complex? Consider using [React](/guide/node-views/react) or [Vue](/guide/node-views/vue), if you have one of those in your project anyway. It gets a little bit easier with those two.
## Adding a content editable
To add editable content to your node view, you need to pass a `contentDOM`, a container element for the content. Here is a simplified version of a node view with non-editable and editable text content:
```js
// Create a container for the node view
const dom = document.createElement('div')
// Give other elements containing text `contentEditable = false`
const label = document.createElement('span')
label.innerHTML = 'Node view'
label.contentEditable = false
// Create a container for the content
const content = document.createElement('div')
// Append all elements to the node view container
dom.append(label, content)
return {
// Pass the node view container …
dom,
// … and the content container:
contentDOM: content,
}
```
Got it? Youre free to do anything you like, as long as you return a container for the node view and another one for the content. Here is the above example in action:
<tiptap-demo name="GuideNodeViews/JavaScriptContent"></tiptap-demo>
Keep in mind that this content is rendered by tiptap. That means you need to tell what kind of content is allowed, for example with `content: 'inline*'` in your node extension (thats what we use in the above example).