Skip to content

perf(editor): stop serializing table markup that carries no information - #1487

Merged
feruzm merged 2 commits into
developfrom
bugfix/slim-table-serialization
Aug 14, 2026
Merged

perf(editor): stop serializing table markup that carries no information#1487
feruzm merged 2 commits into
developfrom
bugfix/slim-table-serialization

Conversation

@feruzm

@feruzm feruzm commented Aug 14, 2026

Copy link
Copy Markdown
Member

The chain prices a comment mostly on history_bytes, which is the serialized transaction size, so wrapper bytes are a direct cost to the author. A 46,620-byte post was recently rejected for insufficient RC, needing more RC than the account's entire maximum, and most of that size was markup that renders identically without it.

What is being removed

TipTap writes colspan="1" rowspan="1" on every cell whether or not it spans anything, and wraps every cell's content in a paragraph:

<td colspan="1" rowspan="1"><p>111,200,584</p></td>

44 bytes of wrapper around 11 bytes of content. Across the 940 cells in that post's two tables: 22,560 bytes of span attributes and 6,580 bytes of paragraph wrappers.

A span of 1 is the default, so it is dropped. A cell whose only child is an unstyled paragraph with no nested block content is unwrapped, since it displays identically.

What is deliberately left alone

This is where the value is, so each case has a spec:

case behaviour
colspan="2", rowspan="3" kept, they mean something
<p style="text-align: right"> in a cell kept, alignment lives on the paragraph
multi-paragraph cell kept, collapsing loses structure
cell holding a list kept
nested table kept, both tables survive
inline formatting preserved through the unwrap

Measured

On the real tables from the post that failed:

TipTap HTML   44,288 bytes
after         15,147 bytes   (66% smaller)
transaction   46,620 -> 17,479 bytes

One intentional consequence

Empty cells now serialize as <td></td> rather than <td><p></p></td>. That is safe because parse-all-extensions-to-doc refills empty cells with a paragraph on load, which is the guard added in #1484 for the paste path. Covered by a spec here too.

Scope

This is the low-risk half of the size problem: pure serialization cleanup with no representational change. The larger win, emitting GFM markdown for tables that can be expressed in it, is a follow-up and needs a capability check so nested tables and block-content cells keep using HTML.

Full suite green: 2707 tests / 281 files. Typecheck clean, no new lint.

The chain prices a comment mostly on history_bytes, which is the
serialized transaction size, so wrapper bytes are a direct cost to the
author. A 46,620-byte post was rejected for insufficient RC needing more
RC than the account's entire maximum, and most of that size was markup
that renders identically without it.

TipTap writes colspan="1" rowspan="1" on every cell whether or not it
spans anything, and wraps every cell's content in a paragraph. On the
two tables in that post: 940 cells carrying 22,560 bytes of span
attributes and 6,580 bytes of paragraph wrappers.

Spans of 1 are the default, so they are dropped. A cell whose only child
is an unstyled paragraph with no nested block content is unwrapped,
since it displays identically. Everything else is left alone: real
spans, alignment on the paragraph, multi-block cells, lists and nested
tables all keep their structure, which is the part that carries meaning.

Measured on the real tables from that post: 44,288 bytes to 15,147, a
66% reduction, taking the whole transaction from 46,620 to 17,479 bytes.

Empty cells now serialize as <td></td>. That is intentional and safe:
parse-all-extensions-to-doc refills them with a paragraph on load, which
is the guard added for the paste path.
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@feruzm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b202bc68-96bd-4a72-8b61-f94d5d9fa540

📥 Commits

Reviewing files that changed from the base of the PR and between 89af621 and 1767240.

📒 Files selected for processing (3)
  • apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts
  • apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts
  • apps/web/src/styles/_markdown.scss

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

qodo-code-review Bot commented Aug 14, 2026

Copy link
Copy Markdown

PR Summary by Qodo

perf(editor): slim TipTap table HTML by removing default spans and wrappers

✨ Enhancement 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Drop redundant table cell attributes (colspan/rowspan="1") to reduce post size.
• Unwrap trivial `` wrappers inside table cells when they carry no formatting.
• Add regression specs covering safe cases (alignment, lists, nested tables, empty cells).
Diagram

graph TD
  F["table-markup-size.spec.ts"] --> B["markdownToHtml()"] --> C["Turndown table rule"] --> D["slimTableMarkup()"] --> E["Slim table HTML"]
  A["TipTap editor getHTML()"] --> B
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Patch TipTap/ProseMirror table serialization (toDOM) to omit defaults
  • ➕ Fixes verbosity at the source for all consumers of editor HTML
  • ➕ Avoids needing DOM post-processing during conversion
  • ➖ Higher maintenance cost (fork/patch vendor code or custom extensions)
  • ➖ Greater regression surface across editor behaviors and upgrades
2. Emit GFM markdown tables when representable, fallback to HTML
  • ➕ Potentially larger size reduction than HTML slimming
  • ➕ More interoperable output for simple tables
  • ➖ Requires capability detection (nested tables, block-content cells, alignment rules)
  • ➖ More complex correctness matrix than HTML normalization
3. Generic HTML minification pass
  • ➕ Broadly reduces bytes across many HTML constructs, not just tables
  • ➕ Reusable optimization layer
  • ➖ Risk of changing semantics/whitespace-sensitive content
  • ➖ Harder to guarantee editor/schema validity on reload

Recommendation: Keep the PR’s targeted table-specific slimming approach: it is low-risk (drops only default spans and unwraps only attribute-free single-paragraph cells) and is backed by explicit specs for alignment, multi-block cells, lists, nested tables, and empty cells. More invasive options (vendor serialization changes or markdown table emission) can be layered later, but should remain separate due to their broader regression surface.

Files changed (2) +179 / -3

Enhancement (1) +47 / -3
markdown-to-html.tsSlim table serialization by removing defaults and unwrapping trivial cell paragraphs +47/-3

Slim table serialization by removing defaults and unwrapping trivial cell paragraphs

• Adds 'slimTableMarkup()' to strip 'colspan/rowspan="1"' and unwrap '<td><p>...</p></td>' when the paragraph is unstyled and contains no nested block content. Hooks this into the Turndown table rule alongside existing 'colgroup' removal to reduce serialized post size without changing rendered output.

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts

Tests (1) +132 / -0
table-markup-size.spec.tsAdd specs validating table markup slimming and edge-case preservation +132/-0

Add specs validating table markup slimming and edge-case preservation

• Introduces Vitest coverage ensuring default spans are removed, meaningful spans are preserved, trivial paragraph wrappers are unwrapped while keeping inline formatting, and structure is retained for alignment, multi-paragraph cells, lists, and nested tables. Also asserts empty cells serialize as '<td></td>' and that realistic tables shrink materially.

apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69fea05998

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +74 to +76
!child.querySelector(CELL_BLOCK_CHILDREN)
) {
cell.innerHTML = child.innerHTML;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep wrappers around paragraphs containing inline images

When a table cell contains an inline image, such as <td><p>before <img ...> after</p></td>, this branch unwraps the paragraph because img is not in CELL_BLOCK_CHILDREN. The publish editor explicitly configures images as inline (use-publish-editor.ts:177-179), while the Ecency stylesheet only overrides Tailwind's block image display under .markdown-view p img (_markdown.scss:133-140). Removing the <p> therefore makes the image render as a block and splits the surrounding cell text across lines, so paragraphs containing images should retain their wrapper.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1767240. img now joins the list of content that requires its wrapper, so a cell containing an image keeps its paragraph and .markdown-view p img { display: inline-block } still applies.

Three specs cover it: before <img> after keeps the paragraph, an image-only cell keeps it too, and a cell that merely mentions the word "image" in text is still unwrapped.

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 14, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Internal extensions module mocked 📘 Rule violation ▣ Testability
Description
The new spec file mocks an internal application module via
vi.mock("@/features/tiptap-editor/extensions", ...), which violates the rule to only mock external
package dependencies in unit tests. This can make tests less representative of real app behavior and
increases brittleness across refactors.
Code

apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3]

+vi.mock("@/features/tiptap-editor/extensions", () => ({
Relevance

●●● Strong

Close precedent: team rejected vi.mock of internal @/ modules; expects avoiding internal module
mocks in specs.

PR-#1456
PR-#865

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668008 restricts mocking to external package dependencies; the test mocks an
internal alias import under @/features/... using vi.mock, replacing real exports with stub
regexes.

Rule 2668008: Mock only external package dependencies with vi.fn in unit tests
apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A unit test mocks an internal application module (`@/features/tiptap-editor/extensions`). Per policy, unit tests should only mock external package dependencies; internal modules should be exercised as-is (or refactored to enable dependency injection) to avoid brittle tests.
## Issue Context
File `apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts` currently contains `vi.mock("@/features/tiptap-editor/extensions", ...)`.
## Fix Focus Areas
- apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3-9]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Internal extensions module mocked ✗ Dismissed 📘 Rule violation ▣ Testability
Description
The new spec file mocks an internal application module via
vi.mock("@/features/tiptap-editor/extensions", ...), which violates the rule to only mock external
package dependencies in unit tests. This can make tests less representative of real app behavior and
increases brittleness across refactors.
Code

apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3]

+vi.mock("@/features/tiptap-editor/extensions", () => ({
Relevance

●●● Strong

Close precedent: team rejected vi.mock of internal @/ modules; expects avoiding internal module
mocks in specs.

PR-#1456
PR-#865

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668008 restricts mocking to external package dependencies; the test mocks an
internal alias import under @/features/... using vi.mock, replacing real exports with stub
regexes.

Rule 2668008: Mock only external package dependencies with vi.fn in unit tests
apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A unit test mocks an internal application module (`@/features/tiptap-editor/extensions`). Per policy, unit tests should only mock external package dependencies; internal modules should be exercised as-is (or refactored to enable dependency injection) to avoid brittle tests.
## Issue Context
File `apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts` currently contains `vi.mock("@/features/tiptap-editor/extensions", ...)`.
## Fix Focus Areas
- apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3-9]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Table typography regression ✓ Resolved 🐞 Bug ≡ Correctness
Description
slimTableMarkup unwraps <td><p>…</p></td> into <td>…</td>, which drops the <p> element that current
markdown CSS targets for paragraph typography. As a result, simple table cells may render with
different line-height/spacing than before, contradicting the PR’s “renders identically” intent.
Code

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[R73-76]

+      child.attributes.length === 0 &&
+      !child.querySelector(CELL_BLOCK_CHILDREN)
+    ) {
+      cell.innerHTML = child.innerHTML;
Relevance

●● Moderate

P-unwrapping could change markdown CSS in tables, but no close precedent found for typography
regressions.

PR-#1484

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR explicitly removes the ` wrapper via cell.innerHTML = child.innerHTML`. The app’s markdown
stylesheet assigns paragraph typography on .markdown-view p (including line-height: 1.55) and
only partially adjusts paragraph spacing inside tables (`.markdown-view table p { margin-bottom: 0;
}), while td/th have no equivalent typography rule—so dropping <p>` can change how cell content
is styled.

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[64-77]
apps/web/src/styles/_markdown.scss[133-141]
apps/web/src/styles/_markdown.scss[242-265]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`slimTableMarkup()` unwraps an unstyled paragraph inside a table cell by setting `cell.innerHTML = child.innerHTML`, removing the `<p>` element entirely. However, our markdown styling applies key typography rules (notably `line-height`) on `.markdown-view p`, not on `td/th`, so unwrapped cell content may render differently.
### Issue Context
- The PR aims to be a pure serialization-size optimization with no rendering changes.
- Current CSS uses paragraph selectors as the typography hook.
### Fix Focus Areas
- apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[64-77]
- apps/web/src/styles/_markdown.scss[133-141]
- apps/web/src/styles/_markdown.scss[242-265]
### Suggested fix options (pick one)
1) **CSS parity (recommended):** Add equivalent typography rules for table cells so `<td>text</td>` matches `<td><p>text</p></td>`.
- Example: in `.markdown-view table { ... }`, add `td, th { line-height: 1.55; }` (and any other p-specific rules you depend on).
2) **Narrow the unwrap:** Keep unwrapping only when the paragraph contains plain text/inline marks *and* you can guarantee no paragraph-specific styling is relied on (harder to prove).
### Acceptance criteria
- A table cell containing a single plain paragraph renders identically before/after (at least for line-height/spacing in the app’s CSS).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (1)
4. Table typography regression ✓ Resolved 🐞 Bug ≡ Correctness
Description
slimTableMarkup unwraps <td><p>…</p></td> into <td>…</td>, which drops the <p> element that current
markdown CSS targets for paragraph typography. As a result, simple table cells may render with
different line-height/spacing than before, contradicting the PR’s “renders identically” intent.
Code

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[R73-76]

+      child.attributes.length === 0 &&
+      !child.querySelector(CELL_BLOCK_CHILDREN)
+    ) {
+      cell.innerHTML = child.innerHTML;
Relevance

●● Moderate

P-unwrapping could change markdown CSS in tables, but no close precedent found for typography
regressions.

PR-#1484

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR explicitly removes the ` wrapper via cell.innerHTML = child.innerHTML`. The app’s markdown
stylesheet assigns paragraph typography on .markdown-view p (including line-height: 1.55) and
only partially adjusts paragraph spacing inside tables (`.markdown-view table p { margin-bottom: 0;
}), while td/th have no equivalent typography rule—so dropping <p>` can change how cell content
is styled.

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[64-77]
apps/web/src/styles/_markdown.scss[133-141]
apps/web/src/styles/_markdown.scss[242-265]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`slimTableMarkup()` unwraps an unstyled paragraph inside a table cell by setting `cell.innerHTML = child.innerHTML`, removing the `<p>` element entirely. However, our markdown styling applies key typography rules (notably `line-height`) on `.markdown-view p`, not on `td/th`, so unwrapped cell content may render differently.
### Issue Context
- The PR aims to be a pure serialization-size optimization with no rendering changes.
- Current CSS uses paragraph selectors as the typography hook.
### Fix Focus Areas
- apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[64-77]
- apps/web/src/styles/_markdown.scss[133-141]
- apps/web/src/styles/_markdown.scss[242-265]
### Suggested fix options (pick one)
1) **CSS parity (recommended):** Add equivalent typography rules for table cells so `<td>text</td>` matches `<td><p>text</p></td>`.
 - Example: in `.markdown-view table { ... }`, add `td, th { line-height: 1.55; }` (and any other p-specific rules you depend on).
2) **Narrow the unwrap:** Keep unwrapping only when the paragraph contains plain text/inline marks *and* you can guarantee no paragraph-specific styling is relied on (harder to prove).
### Acceptance criteria
- A table cell containing a single plain paragraph renders identically before/after (at least for line-height/spacing in the app’s CSS).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Aug 14, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Internal extensions module mocked ✗ Dismissed 📘 Rule violation ▣ Testability
Description
The new spec file mocks an internal application module via
vi.mock("@/features/tiptap-editor/extensions", ...), which violates the rule to only mock external
package dependencies in unit tests. This can make tests less representative of real app behavior and
increases brittleness across refactors.
Code

apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3]

+vi.mock("@/features/tiptap-editor/extensions", () => ({
Relevance

●●● Strong

Close precedent: team rejected vi.mock of internal @/ modules; expects avoiding internal module
mocks in specs.

PR-#1456
PR-#865

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668008 restricts mocking to external package dependencies; the test mocks an
internal alias import under @/features/... using vi.mock, replacing real exports with stub
regexes.

Rule 2668008: Mock only external package dependencies with vi.fn in unit tests
apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A unit test mocks an internal application module (`@/features/tiptap-editor/extensions`). Per policy, unit tests should only mock external package dependencies; internal modules should be exercised as-is (or refactored to enable dependency injection) to avoid brittle tests.

## Issue Context
File `apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts` currently contains `vi.mock("@/features/tiptap-editor/extensions", ...)`.

## Fix Focus Areas
- apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts[3-9]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Table typography regression ✓ Resolved 🐞 Bug ≡ Correctness
Description
slimTableMarkup unwraps <td><p>…</p></td> into <td>…</td>, which drops the <p> element that current
markdown CSS targets for paragraph typography. As a result, simple table cells may render with
different line-height/spacing than before, contradicting the PR’s “renders identically” intent.
Code

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[R73-76]

+      child.attributes.length === 0 &&
+      !child.querySelector(CELL_BLOCK_CHILDREN)
+    ) {
+      cell.innerHTML = child.innerHTML;
Relevance

●● Moderate

P-unwrapping could change markdown CSS in tables, but no close precedent found for typography
regressions.

PR-#1484

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR explicitly removes the <p> wrapper via cell.innerHTML = child.innerHTML. The app’s
markdown stylesheet assigns paragraph typography on .markdown-view p (including `line-height:
1.55) and only partially adjusts paragraph spacing inside tables (.markdown-view table p {
margin-bottom: 0; }), while td/th have no equivalent typography rule—so dropping <p>` can change
how cell content is styled.

apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[64-77]
apps/web/src/styles/_markdown.scss[133-141]
apps/web/src/styles/_markdown.scss[242-265]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`slimTableMarkup()` unwraps an unstyled paragraph inside a table cell by setting `cell.innerHTML = child.innerHTML`, removing the `<p>` element entirely. However, our markdown styling applies key typography rules (notably `line-height`) on `.markdown-view p`, not on `td/th`, so unwrapped cell content may render differently.

### Issue Context
- The PR aims to be a pure serialization-size optimization with no rendering changes.
- Current CSS uses paragraph selectors as the typography hook.

### Fix Focus Areas
- apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts[64-77]
- apps/web/src/styles/_markdown.scss[133-141]
- apps/web/src/styles/_markdown.scss[242-265]

### Suggested fix options (pick one)
1) **CSS parity (recommended):** Add equivalent typography rules for table cells so `<td>text</td>` matches `<td><p>text</p></td>`.
  - Example: in `.markdown-view table { ... }`, add `td, th { line-height: 1.55; }` (and any other p-specific rules you depend on).
2) **Narrow the unwrap:** Keep unwrapping only when the paragraph contains plain text/inline marks *and* you can guarantee no paragraph-specific styling is relied on (harder to prove).

### Acceptance criteria
- A table cell containing a single plain paragraph renders identically before/after (at least for line-height/spacing in the app’s CSS).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 82 rules
✅ Skills: 6 invoked
  add-feature
  add-query
  add-sdk-mutation
  add-test
  code-review
  debug
Review mode: ⚖️ Balanced: This is a behavioral change to editor HTML serialization with meaningful rendering/data-preservation edge cases, but the logic is localized and not dense enough to justify redundant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/web/src/specs/features/tiptap-editor/table-markup-size.spec.ts
Comment thread apps/web/src/features/tiptap-editor/functions/markdown-to-html.ts
Review follow-up. Both findings were correct, and the second one
falsified this PR's central claim that nothing renders differently.

Cells holding an inline image now keep their paragraph. `.markdown-view
p img` sets display:inline-block to keep an image aligned with the text
around it, so promoting the image to a bare cell child loses that and
can break "before <img> after" across lines. `img` joins the list of
content that requires its wrapper.

Unwrapped cells were also losing the typography the `p` rule supplies,
line-height 1.55 and text-rendering optimizeLegibility, so ordinary
tables rendered tighter. Measured at a 700px column: cells went from
42px to 36px, both single-line and wrapped. The table rule now sets the
same values on td and th, which restores an exact match and is a no-op
for cells that kept a paragraph, since the values are identical.

Parity is measured in a headless browser now rather than asserted.
@feruzm
feruzm merged commit dc0b018 into develop Aug 14, 2026
8 checks passed
@feruzm
feruzm deleted the bugfix/slim-table-serialization branch August 14, 2026 08:07
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.

1 participant