
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Overview
The shared TipTap editor (shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue) currently reads and writes Markdown only. Add a format prop — either 'markdown' or 'html', defaulting to 'markdown' — so a consumer can choose to drive the editor with HTML instead. When format is 'html', the editor's value prop is treated as HTML and the update event emits HTML; when it is 'markdown' (the default), behavior is unchanged.
This is needed for the new QTI editor, where the data must be XML rather than Markdown: its rich-text fields are stored as XML strings produced by editor.getHTML(), so the editor has to be able to consume and emit HTML.
Complexity: Low
Target branch: unstable
Context
There is no way for a consumer to get HTML out from the TipTap editor, even though TipTap can produce it directly via editor.getHTML(). The QTI editor (and potentially other consumers) needs HTML/XML, so it requires the editor to (a) accept its value as HTML and (b) emit HTML on update.
The format prop is a transitional measure. In the future, once the QTI editor has replaced the current (Markdown-based) assessment editing, we expect to remove the format prop entirely and have the TipTap editor always consume and emit HTML. The prop exists only so Markdown and HTML consumers can coexist during that transition.
Relevant spots in TipTapEditor.vue:
getMarkdownContent() — the output helper.
watch(() => props.value, ...) — the input/sync-from-parent path (uses preprocessMarkdown).
- the editor-state
watch(() => editor.value?.state, ...) — the sync-to-parent path (emits Markdown).
- the
props block — where value, mode, etc. are declared.
The Change
- Add a
format prop: a string defaulting to 'markdown', accepting only 'markdown' or 'html' (with a prop validator).
- Make the output path format-aware: in
'markdown' it returns storage.markdown.getMarkdown() (current behavior); in 'html' it returns editor.getHTML().
- Make the input path format-aware: in
'markdown' it preprocesses with preprocessMarkdown then sets content (current behavior); in 'html' it sets value as HTML content directly (no Markdown preprocessing).
- The sync-to-parent comparison/emit and the sync-from-parent comparison should use the same format-aware content helper, so the loop-prevention logic keeps working in both formats.
'markdown' remains the default, so all current consumers are unaffected (backward compatible).
Out of Scope
- Changing any current consumer to use
format="html" (this task only adds the capability; the QTI editor will opt in separately).
- Toolbar/feature differences between formats (the same editing features apply; only the serialization in/out changes).
- Markdown-vs-HTML sanitization policy changes beyond what the editor already does.
Acceptance Criteria
General
Accessibility and i18n
Testing
References
shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue — getMarkdownContent(), the props.value watch (input via preprocessMarkdown), the editor-state watch (output via getMarkdown()), and the props block.
editor.getHTML() (TipTap) — the HTML serialization counterpart to the Markdown storage's getMarkdown().
AI usage
I used Claude (Claude Code) to draft this issue. I specified the change; Claude read the current TipTapEditor.vue to ground the description and acceptance criteria, and I reviewed every section.
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
The shared TipTap editor (
shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue) currently reads and writes Markdown only. Add aformatprop — either'markdown'or'html', defaulting to'markdown'— so a consumer can choose to drive the editor with HTML instead. Whenformatis'html', the editor'svalueprop is treated as HTML and theupdateevent emits HTML; when it is'markdown'(the default), behavior is unchanged.This is needed for the new QTI editor, where the data must be XML rather than Markdown: its rich-text fields are stored as XML strings produced by
editor.getHTML(), so the editor has to be able to consume and emit HTML.Complexity: Low
Target branch:
unstableContext
There is no way for a consumer to get HTML out from the TipTap editor, even though TipTap can produce it directly via
editor.getHTML(). The QTI editor (and potentially other consumers) needs HTML/XML, so it requires the editor to (a) accept itsvalueas HTML and (b) emit HTML onupdate.The
formatprop is a transitional measure. In the future, once the QTI editor has replaced the current (Markdown-based) assessment editing, we expect to remove theformatprop entirely and have the TipTap editor always consume and emit HTML. The prop exists only so Markdown and HTML consumers can coexist during that transition.Relevant spots in
TipTapEditor.vue:getMarkdownContent()— the output helper.watch(() => props.value, ...)— the input/sync-from-parent path (usespreprocessMarkdown).watch(() => editor.value?.state, ...)— the sync-to-parent path (emits Markdown).propsblock — wherevalue,mode, etc. are declared.The Change
formatprop: a string defaulting to'markdown', accepting only'markdown'or'html'(with a prop validator).'markdown'it returnsstorage.markdown.getMarkdown()(current behavior); in'html'it returnseditor.getHTML().'markdown'it preprocesses withpreprocessMarkdownthen sets content (current behavior); in'html'it setsvalueas HTML content directly (no Markdown preprocessing).'markdown'remains the default, so all current consumers are unaffected (backward compatible).Out of Scope
format="html"(this task only adds the capability; the QTI editor will opt in separately).Acceptance Criteria
General
TipTapEditor.vuedeclares aformatprop (String) defaulting to'markdown', validated to accept only'markdown'or'html'.format="markdown"(and when the prop is omitted), input and output behavior are unchanged from today (Markdown in, Markdown out) — existing consumers are unaffected.format="html", thevalueprop is treated as HTML and set as editor content without Markdown preprocessing.format="html", theupdateevent emits the editor's HTML (editor.getHTML()).valueand reading backupdateis consistent within'markdown'and within'html'.Accessibility and i18n
Testing
format="markdown"(default) emitting Markdown andformat="html"emitting HTML.formatprop) preserves current Markdown behavior.References
shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue—getMarkdownContent(), theprops.valuewatch (input viapreprocessMarkdown), the editor-state watch (output viagetMarkdown()), and thepropsblock.editor.getHTML()(TipTap) — the HTML serialization counterpart to the Markdown storage'sgetMarkdown().AI usage
I used Claude (Claude Code) to draft this issue. I specified the change; Claude read the current
TipTapEditor.vueto ground the description and acceptance criteria, and I reviewed every section.