Skip to content

Add defaultTextBlockStyles option to createTipTapRichTextBlock - #6366

Closed
VPS-Andreas wants to merge 3 commits into
mainfrom
tiptap-default-text-block-style
Closed

VPS-Andreas wants to merge 3 commits into
mainfrom
tiptap-default-text-block-style

Conversation

@VPS-Andreas

@VPS-Andreas VPS-Andreas commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The text block style dropdown always offered an unstyled Default entry next to the configured textBlockStyles, even for a tag where every instance should always carry one of them, unlike the Draft.js RTE's standardBlockType, which had no such state for the block types it covered.

defaultTextBlockStyles assigns a default style per tag instead: no Default entry is offered for it, a newly created or converted heading/paragraph of that tag gets the style automatically, and the API rejects stored content of that tag missing a style. migrateFromDraftJs falls back to the configured default when a mapped Draft.js block doesn't specify a textBlockStyle. A tag without an entry keeps today's behavior.

A migration that runs after migrateFromDraftJs (for instance one that changes a node's heading level) can leave a node missing its default style, or carrying a style that no longer applies to its new tag, since earlier steps only resolve defaultTextBlockStyles against the tag a node has at that point. A migration is now always appended last to fill in any default still missing, or swap in the default for a style that no longer applies, once every other migration — including a block's own — has applied, so the guarantee holds regardless of what happens in between.

This replaces #6225 (requireTextBlockStyle, a single boolean forcing every applicable tag to require a style, with an implicit "first-in-array-wins" default) and #6004 (defaultTextBlockStyleLabel, a cosmetic rename of the "Default" entry) with one explicit, per-tag mapping — both had grown unclear in scope. Built on top of #6240 (heading-only blocks), now merged.

Example

createTipTapRichTextBlock({
    textBlockStyles: [
        { name: "copy100", appliesTo: ["paragraph"] },
        { name: "copy200", appliesTo: ["paragraph"] },
        { name: "headline300", appliesTo: ["heading-2"] },
    ],
    defaultTextBlockStyles: {
        paragraph: "copy100",
        "heading-2": "headline300",
    },
});

Test plan

🤖 Generated with Claude Code

@VPS-Andreas VPS-Andreas self-assigned this Sep 14, 2026
VPS-Andreas and others added 2 commits September 15, 2026 10:16
The text block style dropdown always offered an unstyled "Default" entry
next to the configured textBlockStyles, even for a tag where every
instance should always carry one of them, unlike the Draft.js RTE's
standardBlockType, which had no such state for the block types it
covered.

defaultTextBlockStyles assigns a default style per tag instead: no
"Default" entry is offered for it, a newly created or converted
heading/paragraph of that tag gets the style automatically, and the API
rejects stored content of that tag missing a style. migrateFromDraftJs
falls back to the configured default when a mapped Draft.js block
doesn't specify a textBlockStyle. A tag without an entry keeps today's
behavior.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A block migration running after migrateFromDraftJs's DraftJS->TipTap
conversion (e.g. one remapping heading levels, like the demo's
Heading1ToHeading2Migration) could leave a node missing its default
style, since only the DraftJS conversion step resolved
defaultTextBlockStyles, against the tag/level a node had at that
point. Found by migrating old DraftJS demo data through the pipeline.

Always append a migration that fills in any default still missing
once every other migration has applied, so the guarantee holds
regardless of what happens in between. Wire defaultTextBlockStyles
into the demo's TipTapRichTextBlock to dogfood the option.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@VPS-Obi

VPS-Obi commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

What do you think about this alternative API?

createTipTapRichTextBlock({
    textBlockStyles: [
        { name: "copy100", appliesTo: ["paragraph"], defaultFor: ["paragraph"] },
        { name: "copy200", appliesTo: ["paragraph"] },
        { name: "headline300", appliesTo: ["heading-2"], defaultFor: ["heading-2"] },
    ],
});

@VPS-Andreas

Copy link
Copy Markdown
Contributor Author

One case worth checking this against: a style that should be the default for several tags, e.g. copy100 for both paragraph and heading-2.

With defaultFor on the style, appliesTo and defaultFor end up listing the same tags twice on one object:

{ name: "copy100", appliesTo: ["paragraph", "heading-2"], defaultFor: ["paragraph", "heading-2"] }

And nothing stops two different style entries from both claiming defaultFor: ["paragraph"] — that conflict could only be caught with validation across all entries.

With defaultTextBlockStyles: Partial<Record<Tag, string>>, the same case is just the same style name under two keys:

defaultTextBlockStyles: {
    paragraph: "copy100",
    "heading-2": "copy100",
},

Since it's a Record, TypeScript already enforces exactly one default per tag — the conflict defaultFor would need runtime validation for can't happen here. I'd keep the current API.

@VPS-Andreas
VPS-Andreas marked this pull request as ready for review September 15, 2026 12:51
@github-actions
github-actions Bot requested a review from VPS-Obi September 15, 2026 12:51
The defaultTextBlockStyles safety-net migration only filled in a missing textBlockStyle. A node whose tag changed after the style was already set (e.g. a heading level bump by a later migration) kept its old style even when that style's appliesTo no longer covers the new tag, breaking the guarantee that a valid default is always applied.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@VPS-Obi
VPS-Obi marked this pull request as draft September 16, 2026 07:53
@VPS-Obi
VPS-Obi removed their request for review September 16, 2026 07:53
@VPS-Andreas

Copy link
Copy Markdown
Contributor Author

Closed in favor of #6382, #6383, #6384

@VPS-Andreas VPS-Andreas closed this Oct 6, 2026
@VPS-Obi
VPS-Obi deleted the tiptap-default-text-block-style branch October 6, 2026 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants