feat: add table support to TipTap editor

Install @tiptap/extension-table packages, register Table/TableRow/
TableHeader/TableCell extensions, add Table button to the More dropdown
(inserts a 3×3 grid), and style tables to match the parchment theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Frederic Cabassut
2026-03-09 23:15:17 +01:00
co-authored by Claude Opus 4.6
parent 108ea21e36
commit 23887c7050
6 changed files with 103 additions and 1 deletions
+1
View File
@@ -26,6 +26,7 @@
- Code blocks (triple backtick)
- Inline code (single backtick)
- Links — insert, edit, and remove with URL input
- Tables (insert 3×3 via toolbar)
- Dividers (horizontal rules)
- Text alignment (left, center, right, justify)
- Line breaks
+4
View File
@@ -34,6 +34,10 @@
"@tiptap/core": "^3.20.1",
"@tiptap/extension-link": "^3.20.1",
"@tiptap/extension-placeholder": "^3.20.1",
"@tiptap/extension-table": "^3.20.1",
"@tiptap/extension-table-cell": "^3.20.1",
"@tiptap/extension-table-header": "^3.20.1",
"@tiptap/extension-table-row": "^3.20.1",
"@tiptap/extension-task-item": "^3.20.1",
"@tiptap/extension-task-list": "^3.20.1",
"@tiptap/extension-text-align": "^3.20.1",
+50
View File
@@ -28,6 +28,18 @@ importers:
'@tiptap/extension-placeholder':
specifier: ^3.20.1
version: 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))
'@tiptap/extension-table':
specifier: ^3.20.1
version: 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)
'@tiptap/extension-table-cell':
specifier: ^3.20.1
version: 3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))
'@tiptap/extension-table-header':
specifier: ^3.20.1
version: 3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))
'@tiptap/extension-table-row':
specifier: ^3.20.1
version: 3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))
'@tiptap/extension-task-item':
specifier: ^3.20.1
version: 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))
@@ -1508,6 +1520,27 @@ packages:
peerDependencies:
'@tiptap/core': ^3.20.1
'@tiptap/extension-table-cell@3.20.1':
resolution: {integrity: sha512-nSeboFey+MJqZuCQSbVUajQVaGiypeoUPiGd0CJdyfc0oPsBGGqp7XFJtw5HHEbDqEvSHvGNDoZDFsUTAxUyIg==}
peerDependencies:
'@tiptap/extension-table': ^3.20.1
'@tiptap/extension-table-header@3.20.1':
resolution: {integrity: sha512-Xsdgik3Bh5xWSkLaPR/6NDLZR5lgUDIN/yiZ7bLtfTsyGxqEvuW2Y9/j/XP3AfsZzGy2/SuA9bM9zxPcFQxwFA==}
peerDependencies:
'@tiptap/extension-table': ^3.20.1
'@tiptap/extension-table-row@3.20.1':
resolution: {integrity: sha512-uYE0SdY4J81wn/fg8Gum0TVSTTBekQhRGeSwDnRfBBd9JILBsLotBTt4ucM7JOUjrP9BjS+QFCT9EstAchPHfQ==}
peerDependencies:
'@tiptap/extension-table': ^3.20.1
'@tiptap/extension-table@3.20.1':
resolution: {integrity: sha512-y2o1De3P/FH80nst1D9pYSwtRvxF87WkNAYGurqCkZ6SjwFq1Ifeh9eY+o79R6SCwcfpvQRytCYd+Yw9o5XAtA==}
peerDependencies:
'@tiptap/core': ^3.20.1
'@tiptap/pm': ^3.20.1
'@tiptap/extension-task-item@3.20.1':
resolution: {integrity: sha512-ZdQld5Jzw/b/zl9TSA3KNkucmQhW5lHS/0YEKb+eFvxMwdHTKSpsTQzrfzbJixcdSqsuKJB+uUCwDDB+l0CRlA==}
peerDependencies:
@@ -4811,6 +4844,23 @@ snapshots:
dependencies:
'@tiptap/core': 3.20.1(@tiptap/pm@3.20.1)
'@tiptap/extension-table-cell@3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))':
dependencies:
'@tiptap/extension-table': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)
'@tiptap/extension-table-header@3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))':
dependencies:
'@tiptap/extension-table': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)
'@tiptap/extension-table-row@3.20.1(@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))':
dependencies:
'@tiptap/extension-table': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)
'@tiptap/extension-table@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)':
dependencies:
'@tiptap/core': 3.20.1(@tiptap/pm@3.20.1)
'@tiptap/pm': 3.20.1
'@tiptap/extension-task-item@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))':
dependencies:
'@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)
+30
View File
@@ -72,3 +72,33 @@ body::before {
.prose :where(a):not(:where([class~="not-prose"] *)):hover {
color: var(--primary-hover);
}
/* Table styles for TipTap editor */
.tiptap table {
border-collapse: collapse;
width: 100%;
margin: 0.5rem 0;
}
.tiptap th,
.tiptap td {
border: 1px solid var(--border-subtle);
padding: 0.375rem 0.625rem;
text-align: left;
vertical-align: top;
min-width: 4rem;
}
.tiptap th {
font-weight: 600;
background-color: color-mix(in srgb, var(--bg-base) 60%, transparent);
}
.tiptap td p,
.tiptap th p {
margin: 0;
}
.tiptap .selectedCell {
background-color: color-mix(in srgb, var(--primary) 12%, transparent);
}
+10 -1
View File
@@ -23,7 +23,8 @@
AlignJustify,
Minus,
ChevronDown,
Ellipsis
Ellipsis,
Table2
} from 'lucide-svelte';
interface Props {
@@ -338,6 +339,14 @@
<CodeXml size={iconSize} />
<span>Code block</span>
</button>
<button
onclick={() => { editor?.chain().focus().insertTable({ rows: 3, cols: 3 }).run(); closeDropdowns(); }}
class={dropdownItemClass()}
data-testid="format-table"
>
<Table2 size={iconSize} />
<span>Table</span>
</button>
<button
onclick={() => { editor?.chain().focus().setHorizontalRule().run(); closeDropdowns(); }}
class={dropdownItemClass()}
+8
View File
@@ -6,6 +6,10 @@
import Underline from '@tiptap/extension-underline';
import TextAlign from '@tiptap/extension-text-align';
import Placeholder from '@tiptap/extension-placeholder';
import { Table } from '@tiptap/extension-table';
import { TableRow } from '@tiptap/extension-table-row';
import { TableHeader } from '@tiptap/extension-table-header';
import { TableCell } from '@tiptap/extension-table-cell';
import { Markdown } from 'tiptap-markdown';
interface Props {
@@ -30,6 +34,10 @@
Underline,
TextAlign.configure({ types: ['heading', 'paragraph'] }),
Placeholder.configure({ placeholder }),
Table.configure({ resizable: false }),
TableRow,
TableHeader,
TableCell,
Markdown
],
content,