Text Editor - Details Plugin
A collapsible details/summary block that round-trips as plain HTML.
#Usage
import { TextEditor } from '@primeui/vue-texteditor';
import { detailsPlugin } from './details-plugin';<TextEditor.Root v-model="value" :plugins="[detailsPlugin]">
<TextEditor.Toolbar v-slot="{ plugins }">
<button @click="plugins.details?.insert('Summary')">Collapsible</button>
</TextEditor.Toolbar>
<TextEditor.Content />
</TextEditor.Root>The Details plugin adds a collapsible <details>/<summary> block. It is a schema-extension plugin: through the optional third argument of defineTextEditorPlugin, it contributes three nodes (details, details_summary, details_content) to the per-instance schema. The open attribute round-trips through the standard HTML <details open> serialization, so the document value stays plain HTML with no custom markup.
#Commands
| Command | Signature | Description |
|---|---|---|
insert | (summaryText?: string) => void | Insert a collapsible block with the given summary |
#Plugin Definition
This plugin contributes nodes via the schema option. The key part:
import { defineTextEditorPlugin } from '@primeui/vue-texteditor';
import type { NodeSpec } from 'prosemirror-model';
const details: NodeSpec = {
group: 'block',
content: 'details_summary details_content',
defining: true,
attrs: { open: { default: true } },
parseDOM: [{ tag: 'details', getAttrs: (n) => ({ open: (n as HTMLElement).hasAttribute('open') }) }],
toDOM: (node) => (node.attrs.open ? ['details', { open: '' }, 0] : ['details', {}, 0])
};
export const detailsPlugin = defineTextEditorPlugin(
'details',
(ctx) => ({
commands: {
insert: (summaryText = 'Details') => {
const view = ctx.getView();
if (!view) return;
const { schema } = view.state;
const summary = schema.nodes.details_summary.create(null, summaryText ? schema.text(summaryText) : undefined);
const content = schema.nodes.details_content.create(null, schema.nodes.paragraph.create());
const node = schema.nodes.details.create({ open: true }, [summary, content]);
view.dispatch(view.state.tr.replaceSelectionWith(node).scrollIntoView());
view.focus();
}
}
}),
{ schema: { nodes: { details, details_summary: detailsSummary, details_content: detailsContent } } }
);Style the block to match the active theme:
.p-text-editor-body details {
border: 1px solid var(--p-surface-300);
border-radius: 6px;
padding: 0.5rem 0.75rem;
}
.p-text-editor-body details summary {
cursor: pointer;
font-weight: 600;
}#Example
Click Insert Collapsible Section, or click a summary to toggle it.
Loading Demo...