Skip to content

[QTI/RTE] Add a format prop to the TipTap editor to support HTML input/output #5966

@AlexVelezLl

Description

@AlexVelezLl

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

  • TipTapEditor.vue declares a format prop (String) defaulting to 'markdown', validated to accept only 'markdown' or 'html'.
  • With format="markdown" (and when the prop is omitted), input and output behavior are unchanged from today (Markdown in, Markdown out) — existing consumers are unaffected.
  • With format="html", the value prop is treated as HTML and set as editor content without Markdown preprocessing.
  • With format="html", the update event emits the editor's HTML (editor.getHTML()).
  • The sync-from-parent and sync-to-parent paths both use the format-aware content helper, so external updates and the loop-prevention flag work correctly in both formats.
  • Content round-trips in each format: setting value and reading back update is consistent within 'markdown' and within 'html'.

Accessibility and i18n

  • No user-facing strings are added; if any are, they come from the editor's existing strings module.

Testing

  • Unit tests cover format="markdown" (default) emitting Markdown and format="html" emitting HTML.
  • A test confirms the default (no format prop) preserves current Markdown behavior.
  • Existing lint and test suites pass.

References

  • shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vuegetMarkdownContent(), 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Task.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions