---
tableOfContents: true
---
# Node views with React
## Introduction
Using Vanilla JavaScript can feel complex if you are used to work in React. Good news: You can use regular React components in your node views, too. There is just a little bit you need to know, but let’s go through this one by one.
## Render a React component
Here is what you need to do to render React components inside your editor:
1. [Create a node extension](/guide/custom-extensions)
2. Create a React component
3. Pass that component to the provided `ReactNodeViewRenderer`
4. Register it with `addNodeView()`
5. [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 { ReactNodeViewRenderer } from '@tiptap/react'
import Component from './Component.jsx'
export default Node.create({
// configuration …
addNodeView() {
return ReactNodeViewRenderer(Component)
},
})
```
There is a little bit of magic required to make this work. But don’t worry, we provide a wrapper component you can use to get started easily. Don’t forget to add it to your custom React component, like shown below:
```html
React Component
```
Got it? Let’s see it in action. Feel free to copy the below example to get started.
https://embed.tiptap.dev/preview/GuideNodeViews/ReactComponent
That component doesn’t interact with the editor, though. Time to wire it up.
## Access node attributes
The `ReactNodeViewRenderer` which you use in your node extension, passes a few very helpful props to your custom React component. One of them is the `node` prop. Let’s say you have [added an attribute](/guide/custom-extensions#attributes) named `count` to your node extension (like we did in the above example) you could access it like this:
```js
props.node.attrs.count
```
## Update node attributes
You can even update node attributes from your node, with the help of the `updateAttributes` prop passed to your component. Pass an object with updated attributes to the `updateAttributes` prop:
```js
export default props => {
const increase = () => {
props.updateAttributes({
count: props.node.attrs.count + 1,
})
}
// …
}
```
And yes, all of that is reactive, too. A pretty seemless communication, isn’t it?
## Adding a content editable
There is another component called `NodeViewContent` which helps you adding editable content to your node view. Here is an example:
```jsx
import React from 'react'
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'
export default () => {
return (
React Component
)
}
```
You don’t need to add those `className` attributes, feel free to remove them or pass other class names. Try it out in the following example:
https://embed.tiptap.dev/preview/GuideNodeViews/ReactComponentContent
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 (that’s what we use in the above example).
The `NodeViewWrapper` and `NodeViewContent` components render a `
` HTML tag (`` for inline nodes), but you can change that. For example `` should render a paragraph. One limitation though: That tag must not change during runtime.
## Changing the default content tag for a node view
By default a node view rendered by `ReactNodeViewRenderer` will always have a wrapping `div` inside. If you want to change the type of this node, you can the `contentDOMElementTag` to the `ReactNodeViewRenderer` options:
```js
// this will turn the div into a header tag
return ReactNodeViewRenderer(Component, { contentDOMElementTag: 'header' })
```
## All available props
Here is the full list of what props you can expect:
### editor
The editor instance
### node
The current node
### decorations
An array of decorations
### selected
`true` when there is a `NodeSelection` at the current node view
### extension
Access to the node extension, for example to get options
### getPos()
Get the document position of the current node
### updateAttributes()
Update attributes of the current node
### deleteNode()
Delete the current node
## Dragging
To make your node views draggable, set `draggable: true` in the extension and add `data-drag-handle` to the DOM element that should function as the drag handle.