Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/2026-08-11-table-default-spans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tiptap/extension-table': patch
---

Table cells and headers only serialize `colspan` and `rowspan` when a cell spans more than one column or row.
22 changes: 22 additions & 0 deletions packages/extension-table/__tests__/tableCell.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ describe('extension table cell', () => {
getEditorEl()?.remove()
})

it('should only render colspan and rowspan when they are not the default', () => {
const content =
'<table><tbody><tr><td>Name</td><td colspan="2">Description</td></tr><tr><td rowspan="2">Cyndi Lauper</td><td>Singer</td><td>Songwriter</td></tr></tbody></table>'

editor = new Editor({
element: createEditorEl(),
extensions: [Document, Text, Paragraph, TableCell, TableHeader, TableRow, Table],
content,
})

const html = editor.getHTML()

expect(html).toContain('<td><p>Name</p></td>')
expect(html).toContain('<td colspan="2"><p>Description</p></td>')
expect(html).toContain('<td rowspan="2"><p>Cyndi Lauper</p></td>')
expect(html).not.toContain('colspan="1"')
expect(html).not.toContain('rowspan="1"')

editor?.destroy()
getEditorEl()?.remove()
})

it('should prefer the colwidth attribute over the colgroup col width', () => {
const content =
'<table><colgroup><col width="64" /><col /></colgroup><tbody><tr><td colwidth="200">hello</td><td>world</td></tr></tbody></table>'
Expand Down
4 changes: 2 additions & 2 deletions packages/extension-table/__tests__/tableCommands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,15 +268,15 @@ describe('Table commands', () => {
editor.commands.clearContent()
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: false })
expect(editor.getHTML()).toBe(
'<table style="min-width: 25px;"><colgroup><col style="min-width: 25px;"></colgroup><tbody><tr><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>',
'<table style="min-width: 25px;"><colgroup><col style="min-width: 25px;"></colgroup><tbody><tr><td><p></p></td></tr></tbody></table>',
)
})

it('generates correct markup for a 1x1 table with header', () => {
editor.commands.clearContent()
editor.commands.insertTable({ cols: 1, rows: 1, withHeaderRow: true })
expect(editor.getHTML()).toBe(
'<table style="min-width: 25px;"><colgroup><col style="min-width: 25px;"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p></p></th></tr></tbody></table>',
'<table style="min-width: 25px;"><colgroup><col style="min-width: 25px;"></colgroup><tbody><tr><th><p></p></th></tr></tbody></table>',
)
})

Expand Down
22 changes: 22 additions & 0 deletions packages/extension-table/__tests__/tableHeader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ describe('extension table header', () => {
getEditorEl()?.remove()
})

it('should only render colspan and rowspan when they are not the default', () => {
const content =
'<table><tbody><tr><th>Name</th><th colspan="2">Description</th></tr><tr><th rowspan="2">Cyndi Lauper</th><td>Singer</td><td>Songwriter</td></tr><tr><td>Marie Curie</td><td>Scientist</td></tr></tbody></table>'

editor = new Editor({
element: createEditorEl(),
extensions: [Document, Text, Paragraph, TableCell, TableHeader, TableRow, Table],
content,
})

const html = editor.getHTML()

expect(html).toContain('<th><p>Name</p></th>')
expect(html).toContain('<th colspan="2"><p>Description</p></th>')
expect(html).toContain('<th rowspan="2"><p>Cyndi Lauper</p></th>')
expect(html).not.toContain('colspan="1"')
expect(html).not.toContain('rowspan="1"')

editor?.destroy()
getEditorEl()?.remove()
})

it('should parse the colgroup col widths for a header row', () => {
const content =
'<table><colgroup><col width="64" /><col width="128" /></colgroup><tbody><tr><th>Name</th><th>Description</th></tr><tr><td>Cyndi Lauper</td><td>Singer</td></tr></tbody></table>'
Expand Down
18 changes: 18 additions & 0 deletions packages/extension-table/src/cell/table-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,27 @@ export const TableCell = Node.create<TableCellOptions>({
return {
colspan: {
default: 1,
renderHTML: attributes => {
if (attributes.colspan === 1) {
return {}
}

return {
colspan: attributes.colspan,
}
},
},
rowspan: {
default: 1,
renderHTML: attributes => {
if (attributes.rowspan === 1) {
return {}
}

return {
rowspan: attributes.rowspan,
}
},
},
colwidth: {
default: null,
Expand Down
18 changes: 18 additions & 0 deletions packages/extension-table/src/header/table-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,27 @@ export const TableHeader = Node.create<TableHeaderOptions>({
return {
colspan: {
default: 1,
renderHTML: attributes => {
if (attributes.colspan === 1) {
return {}
}

return {
colspan: attributes.colspan,
}
},
},
rowspan: {
default: 1,
renderHTML: attributes => {
if (attributes.rowspan === 1) {
return {}
}

return {
rowspan: attributes.rowspan,
}
},
},
colwidth: {
default: null,
Expand Down
Loading