CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tiptap--vue-3

Vue 3 components and composables for building rich text editors with tiptap

Pending
Overview
Eval results
Files

vue-components.mddocs/

Vue Components

Vue 3 components for rendering editor content and UI elements with full integration into Vue's component system.

Capabilities

EditorContent Component

The main component for rendering the editor's content area where users can type and edit text.

/**
 * Vue component that renders the editor content area
 * Handles editor mounting and Vue context integration
 */
const EditorContent: DefineComponent<{
  /** The editor instance to render content for */
  editor: {
    type: PropType<Editor>;
    default: null;
  };
}>;

Key Features:

  • Automatically mounts editor to DOM element
  • Integrates Vue app context and provides
  • Handles editor lifecycle synchronization
  • Creates ProseMirror node views

Usage Examples:

<template>
  <div>
    <EditorContent :editor="editor" />
  </div>
</template>

<script setup>
import { useEditor, EditorContent } from "@tiptap/vue-3";
import StarterKit from "@tiptap/starter-kit";

const editor = useEditor({
  content: '<p>Hello World!</p>',
  extensions: [StarterKit],
});
</script>

NodeViewContent Component

Component for rendering the content area within custom node views.

/**
 * Component for rendering node view content areas
 * Used inside custom node view components
 */
const NodeViewContent: DefineComponent<{
  /** HTML tag to render as */
  as?: {
    type: PropType<string>;
    default: 'div';
  };
}>;

Key Features:

  • Pre-configured with white-space: pre-wrap styling
  • Marked with data-node-view-content attribute
  • Customizable HTML tag via as prop

Usage Examples:

<!-- In a custom node view component -->
<template>
  <div class="my-custom-node">
    <h3>Custom Node</h3>
    <NodeViewContent as="div" />
  </div>
</template>

<script setup>
import { NodeViewContent } from "@tiptap/vue-3";
</script>

NodeViewWrapper Component

Wrapper component for custom node views that handles drag events and decorations.

/**
 * Wrapper component for custom node views
 * Handles drag events and decoration styling
 */
const NodeViewWrapper: DefineComponent<{
  /** HTML tag to render as */
  as?: {
    type: PropType<string>;
    default: 'div';
  };
}>;

Injected Dependencies:

  • onDragStart: Function - Drag start event handler
  • decorationClasses: String - CSS classes for ProseMirror decorations

Key Features:

  • Handles drag and drop events
  • Applies ProseMirror decoration classes
  • Marked with data-node-view-wrapper attribute
  • Normalizes white-space styling

Usage Examples:

<!-- In a custom node view component -->
<template>
  <NodeViewWrapper as="article" class="my-wrapper">
    <div class="node-header">
      <button @click="deleteNode">Delete</button>
    </div>
    <NodeViewContent />
  </NodeViewWrapper>
</template>

<script setup>
import { NodeViewContent, NodeViewWrapper } from "@tiptap/vue-3";
import { inject } from 'vue';

// Access injected dependencies
const onDragStart = inject('onDragStart');
const decorationClasses = inject('decorationClasses');

// Node view props are automatically provided
const props = defineProps(nodeViewProps);

const deleteNode = () => {
  props.deleteNode();
};
</script>

Component Integration Patterns

Slot Usage:

<template>
  <NodeViewWrapper>
    <!-- Default slot content -->
    <div class="custom-content">
      <NodeViewContent />
    </div>
  </NodeViewWrapper>
</template>

Styling Integration:

<template>
  <NodeViewWrapper class="prose-node" :class="additionalClasses">
    <NodeViewContent class="content-area" />
  </NodeViewWrapper>
</template>

<style scoped>
.prose-node {
  border: 1px solid #e5e7eb;
  border-radius: 0.375rem;
  padding: 1rem;
}

.content-area {
  min-height: 2rem;
  outline: none;
}
</style>

Event Handling:

<template>
  <NodeViewWrapper @click="handleClick" @keydown="handleKeydown">
    <div class="toolbar">
      <button @click="updateAttributes({ alignment: 'left' })">Left</button>
      <button @click="updateAttributes({ alignment: 'center' })">Center</button>
    </div>
    <NodeViewContent />
  </NodeViewWrapper>
</template>

<script setup>
import { nodeViewProps } from "@tiptap/vue-3";

const props = defineProps(nodeViewProps);

const handleClick = (event) => {
  console.log('Node clicked', event);
};

const handleKeydown = (event) => {
  if (event.key === 'Delete') {
    props.deleteNode();
  }
};
</script>

Types

interface NodeViewProps {
  editor: Editor;
  node: ProseMirrorNode;
  decorations: DecorationWithType[];
  selected: boolean;
  extension: Node;
  getPos: () => number | undefined;
  updateAttributes: (attributes: Record<string, any>) => void;
  deleteNode: () => void;
  view: EditorView;
  innerDecorations: DecorationSource;
  HTMLAttributes: Record<string, any>;
}

const nodeViewProps: {
  editor: { type: PropType<NodeViewProps['editor']>; required: true };
  node: { type: PropType<NodeViewProps['node']>; required: true };
  decorations: { type: PropType<NodeViewProps['decorations']>; required: true };
  selected: { type: PropType<NodeViewProps['selected']>; required: true };
  extension: { type: PropType<NodeViewProps['extension']>; required: true };
  getPos: { type: PropType<NodeViewProps['getPos']>; required: true };
  updateAttributes: { type: PropType<NodeViewProps['updateAttributes']>; required: true };
  deleteNode: { type: PropType<NodeViewProps['deleteNode']>; required: true };
  view: { type: PropType<NodeViewProps['view']>; required: true };
  innerDecorations: { type: PropType<NodeViewProps['innerDecorations']>; required: true };
  HTMLAttributes: { type: PropType<NodeViewProps['HTMLAttributes']>; required: true };
};

Install with Tessl CLI

npx tessl i tessl/npm-tiptap--vue-3

docs

core-editor-api.md

editor-management.md

index.md

menu-components.md

vue-components.md

vue-renderers.md

tile.json