Text Editor - Setup

Install Vue TextEditor, load TextEditor styles, and add optional PrimeUI or Tailwind UI parts.

#Installation

Install the Vue TextEditor runtime package.

npm install @primeui/vue-texteditor

#Dependencies

@primeui/vue-texteditor is the only package to install. It brings the TextEditor runtime helpers, shared types, and style package through its package dependencies.

TextEditor is not a wrapper around another editor library. It is built on ProseMirror as its low-level toolkit for document modeling, transactions, and view rendering. ProseMirror packages are included as dependencies and installed automatically.

PrimeUI and Tailwind UI parts are optional application-owned components. Add one UI layer for maintained toolbar, block menu, slash menu, mention, image upload, and table visuals without writing every surface from scratch.

#Import

Import the TextEditor namespace from the Vue package.

import { TextEditor } from '@primeui/vue-texteditor';

#Styles

Load the core structural stylesheet once in the app entry, together with a theme file. TextEditor ships two built-in themes: default.css (static values) and primeone.css (derived from a PrimeUI library's design tokens). Pick primeone.css together with a PrimeUI library so the editor matches the rest of the app.

#Default

import '@primeui/texteditor-style/themes/default.css';
import '@primeui/texteditor-style/style.css';

#PrimeOne

import '@primeui/texteditor-style/themes/primeone.css';
import '@primeui/texteditor-style/style.css';

The core file owns layout, focus rings, positioning, and interaction states. The theme file maps TextEditor variables to either static values or PrimeOne tokens. Neither file installs toolbar buttons, block menu bodies, slash menus, or upload widgets.

Use Theming for the complete style import and CSS variable reference.

#UI Parts

The TextEditor runtime is template-first. It exposes parts such as TextEditor.Root, TextEditor.Toolbar, TextEditor.Content, TextEditor.BlockMenu, TextEditor.SlashMenu, TextEditor.ImageUpload, and TextEditor.MentionMenu. Each part renders an empty TextEditor-owned surface, exposes its commands and state through slot props along with a matching useXxxContext() accessor, and lets the app provide the visible UI.

UI parts are copied into the project, so teams can edit, restyle, or replace them. The set covers ToolbarUI, BlockControlsUI, BlockMenuUI, ContextToolbarUI, BlockSlashMenuUI, MentionListUI, ImageUploadDropzoneUI, DocumentUploadDropzoneUI, UploadProgressUI, TableControlsUI, the table column, row, and cell option widgets, plus NavigatorTriggerUI and NavigatorMenuUI.

Two terms recur here. PrimeOne is the theme and token system — the primeone.css stylesheet and the --ui primeone CLI flag. The PrimeUI parts are the copied UI components that match that theme. The CLI flag --ui primeone copies the PrimeUI parts; --ui tailwind copies the Tailwind variant.

UI layerUse whenStyling model
PrimeUIThe app already uses PrimeUI tokens or should match PrimeOne component styling.Component CSS plus TextEditor variables mapped to PrimeOne tokens.
TailwindThe app owns its visual system through Tailwind utilities and wants editable SFC parts.Utility classes inside copied Vue components, with TextEditor structural CSS below.
CustomThe product needs fully bespoke toolbar, menu, or upload widgets.Application components that read TextEditor context hooks.

#CLI

The CLI can copy either PrimeOne or Tailwind TextEditor parts into your project.

#PrimeOne

Run the CLI from the project root to copy the PrimeOne parts. --output-dir sets their parent directory, so this command writes to src/components/primeui/texteditor.

npx -y @primeui/cli add texteditor --framework vue --ui primeone --output-dir ./src/components/primeui

Add the copied component stylesheet after the TextEditor theme and core styles. This example uses @/ as an alias for src/.

import '@primeui/texteditor-style/themes/primeone.css';
import '@primeui/texteditor-style/style.css';
import '@/components/primeui/texteditor/assets/style/components.css';

#Tailwind

If the project already uses Tailwind, copy the utility-class variant instead.

npx -y @primeui/cli add texteditor --framework vue --ui tailwind --output-dir ./src/components/primeui

The Tailwind parts keep their styles in the component markup, so there is no additional component stylesheet. Load the default theme and core stylesheet:

import '@primeui/texteditor-style/themes/default.css';
import '@primeui/texteditor-style/style.css';

#Usage

Compose the editor from TextEditor.Root, TextEditor.Toolbar, and TextEditor.Content. Bind the value with v-model. Place a custom toolbar widget inside TextEditor.Toolbar. The widget reads commands and state from useTextEditorContext().

<TextEditor.Root v-model="value">
    <TextEditor.Toolbar>
        <MyToolbar />
    </TextEditor.Toolbar>
    <TextEditor.Content />
</TextEditor.Root>

The widget pulls commands and state from the editor context, so there is no prop drilling.

<!-- MyToolbar.vue -->
<script setup lang="ts">
import { useTextEditorContext } from '@primeui/vue-texteditor';

const { commands, state } = useTextEditorContext();
</script>

<template>
    <button @click="commands.bold()" :aria-pressed="state.bold">B</button>
    <button @click="commands.italic()" :aria-pressed="state.italic">I</button>
</template>

#Alternative: inline with slot props

For one-off prototyping, the same data is also surfaced as slot props. Useful when splitting the toolbar into its own file isn't worth it.

<TextEditor.Root v-model="value">
    <TextEditor.Toolbar v-slot="{ commands, state }">
        <button @click="commands.bold()" :aria-pressed="state.bold">B</button>
    </TextEditor.Toolbar>
    <TextEditor.Content />
</TextEditor.Root>

TextEditor.Root accepts mode, placeholder, markdown, minTableColumnWidth, defaultTableColumnWidth, and plugins, plus the form-integration props name, required, disabled, and readonly, and the accessibility props ariaLabel / ariaLabelledby. When name is set, Root renders a hidden <input> mirrored to the current value so the editor participates in native <form> submission. Output formats are available both on Root's default slot (getHTML, getBlocks, getJSON, getText, getMarkdown, setValue) and via useTextEditorContext() for descendant widgets.

The placeholder prop sets hint text shown while the editor is empty. In classic mode it appears on the empty editor; in block mode it appears inside the focused empty block.

Always give the editor an accessible name via ariaLabel or ariaLabelledby (see Accessibility). For very large documents, set valueChangeDebounce (milliseconds) to coalesce the value-change emission — the editor re-serializes the whole document on each change, so a small debounce (e.g. 150) avoids per-keystroke serialization cost. The default is 0 (emit immediately). When disabled or readonly is set, document-mutating commands are blocked even if triggered programmatically, and the content stays selectable and copyable.

Start with the template-first TextEditor structure, then add style imports and UI parts from the setup steps around it. The runtime parts stay the same whether the visible UI comes from PrimeUI parts or app-owned components.

Loading Demo...

#Quickstarts

Explore the runnable projects in the TextEditor examples repository. Each quickstart includes a working rich text editor configured with editable UI parts.

  • Vite - Vue and Vite with PrimeOne UI parts and PrimeVue controls.
  • Nuxt - Nuxt with PrimeOne UI parts and PrimeVue controls.
  • Vite + Tailwind - Vue and Vite with Tailwind UI parts and native controls.
  • Nuxt + Tailwind - Nuxt with Tailwind UI parts and native controls.