Text Editor - Invisible Characters Plugin
Toggle visible markers for spaces and paragraph breaks.
#Usage
import { TextEditor } from '@primeui/vue-texteditor';
import { invisibleCharsPlugin } from './invisible-chars-plugin';<TextEditor.Root v-model="value" :plugins="[invisibleCharsPlugin]">
<TextEditor.Toolbar v-slot="{ plugins }">
<button @click="plugins.invisibleChars?.toggle()">Invisible Characters</button>
</TextEditor.Toolbar>
<TextEditor.Content />
</TextEditor.Root>The Invisible Characters plugin renders a · for each space and a ¶ at the end of each text block, making whitespace and paragraph boundaries visible. The markers are widget decorations held in the plugin's own state via a meta transaction and never enter the document, so the value stays clean. The toggle command shows and hides them.
#Commands
| Command | Signature | Description |
|---|---|---|
show | () => void | Show the markers |
hide | () => void | Hide the markers |
toggle | () => void | Toggle marker visibility |
isEnabled | () => boolean | Whether the markers are currently shown |
#Plugin Definition
import { defineTextEditorPlugin } from '@primeui/vue-texteditor';
import { Plugin, PluginKey } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view';
const key = new PluginKey('invisibleChars');
// buildDecorations(state) walks the doc, adding a widget '·' after each space
// and a '¶' at the end of every text block, then returns a DecorationSet.
export const invisibleCharsPlugin = defineTextEditorPlugin('invisibleChars', (ctx) => {
const remove = ctx.registerProseMirrorPlugin(
new Plugin({
key,
state: {
init: () => ({ enabled: false, decorations: DecorationSet.empty }),
apply(tr, value, _old, newState) {
const toggle = tr.getMeta(key);
const enabled = toggle ?? value.enabled;
if (!enabled) return { enabled, decorations: DecorationSet.empty };
if (toggle === true || (tr.docChanged && value.enabled)) {
return { enabled, decorations: buildDecorations(newState) };
}
return { enabled, decorations: value.decorations.map(tr.mapping, tr.doc) };
}
},
props: { decorations: (state) => key.getState(state)?.decorations }
})
);
ctx.onUnmounted(remove);
return {
commands: {
toggle: () => {
const view = ctx.getView();
if (!view) return;
const on = key.getState(view.state)?.enabled ?? false;
view.dispatch(view.state.tr.setMeta(key, !on));
}
// show / hide / isEnabled omitted for brevity
}
};
});#Example
Click Toggle Invisible Characters to reveal spaces and paragraph breaks.
Loading Demo...