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

CommandSignatureDescription
insert(summaryText?: string) => voidInsert 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...