As an administrative note, I will delete all non-substantive comments from this thread to cut down the clutter and mass emails to everyone. Please use the Reaction feature to show support.
Right now I'm taking Quill as the first option to use in a big education related software, but the support for tables is a "deal breaker", is there any progress in the implementation of this feature?
From some preliminary research, tables are going to be complex to implement and probably won't be added in the immediate future.
@jhchen thanks for the answer, I understand. Thanks anyway, QuillJS looks really promising, will keep an eye on it and see if I can contribute with something.
Table editor in closure library for reference
https://rawgit.com/google/closure-library/master/closure/goog/demos/editor/tableeditor.html
I would need that for my project too. I think I can spend some time on this, if someone can advice me some API endpoints or something. Where should I begin with ?
quill supports tabs and automatically expand and shrink the width of each block when adding/removing text.
Maybe we can define columns with tabs and add the table borders as a layer ontop of the text.
The column width in the table can be synced with the width of the text in each block separated by tabs.
Column width in all rows should be synced. Maybe a custom element can be inserted with a configurable width. (similar to how images are inserted).
| First Header (tab) | Second Header (tab) |
| --- | --- |
| Content from cell 1 (tab) | Content from cell 2 (tab) |
| Content in the first column (tab) | Content in the second column (tab) |
A simple table GUI to add/remove rows and columns might be enough:
https://wymeditor.github.io/wymeditor/dist/examples/21-table-plugin.html
would it be possible to allow pasting of tables to not convert them to divs? tried to add the tags to the normalizer whitelist, but it still converted them. I don't mind working with a tweaked core lib until 1.0 is out. Any kind of direction would be greatly appreciated!
I really want to take this on but I have some questions. The first one being that I'm really curious what thoughts @jhchen and @george-norris-salesforce have about how to go about doing this. The way I see it there are three levels of support: 1. Handling pasted tables. 2. Providing APIs for interacting with tables 3. Adding UI support for tables
<table> ,<thead>, <tbody>, <tr> and <th>The next level is the hard part!
And finally
Oh and one last thing: how about a Quill slack team?
Adding tables would be a great addition to Quill, both in beneficial impact but also work required.
I think the key to success here is to start small. So I would scope the initial feature set to:
The first major decision is whether tables should be defined/implemented with multiple Blots (like how lists are implemented) or a single Embed Blot (like formulas or videos). The latter is more straightforward but also more constraining but as a starting point of the discussion we'll start here.
For reference, an expected table would look like this:
<table>
<tbody>
<tr>
<td>A1</td>
<td>B1</td>
<td>C1</td>
</tr>
<tr>
<td>A2</td>
<td>B2</td>
<td>C2</td>
</tr>
</tbody>
</table>
Inserting such a table could look like this:
insertEmbed(index, 'table', [
['A1', 'B1', 'C1'],
['A2', 'B2', 'C2']
]);
Deleting the table can use the existing deleteText with appropriate index.
Embeds currently have the limitation that they cannot be updated--one would delete and insert a new table to update. This also more so affects large tables and realtime collaboration use cases. Some sort of update semantic for embeds could probably be introduced to Deltas and tables can just piggyback off of that. The only ramification I can think of is it may standardize around using objects so our definition might change to:
insertEmbed(index, 'table', {
'1': {
'1': 'A1', '2': 'B1', '3': 'C1'
},
'2': {
'1': 'A2', '2': 'B2', '3': 'C2'
}
});
// Theoretical update embed
updateEmbed(index, {
'1': {
'3': 'Updated C1 value'
}
});
The keys dont neccessarily have to be indexes and can be used to bear more meaning, for example to indicate header status.
The other major limitation to implementing as an Embed Blot is: it is not clear how to support formatting within cells. I personally don't think it's a good idea to nest complex formats inside a small table cell anyways but simple formats like bolding within cells seem reasonable. Perhaps this could be an acceptable limitation of an inital table implementation however.
Implementing tables as multple blots would have neither of Embed Blot's limitations, but introduces more decision points to clear up ambiguity it introduces:
There are a lot of paths here and I would encourage others interested to try and prototype one of these routes and report any unexpected issues or unexpected lack of issues.
Once a table is defined with Parchment, pasting should just work since initialization actually uses the clipboard.convert function. The only additional effort is if Quill's tables support a subset of HTML table feature (which will be the case) and you'd like to handle this specially. For example, if the above Embed Blot implementation route is taken without special treatment of <thead> Quill will just clump that with regular <tbody> rows, but if you'd rather strip <thead> content for some reason, you would implement a custom clipboard matcher.
To be clear tables need to coexist within the Delta format and semantic. Otherwise general and important methods like getContents, updateContents, setContents would break. With this satisfied, I don't see a need for top level table specific APIs. No other format requires this and it's not clear why tables would be special.
As far as UI I think doing what existing products like Word/Docs does is a good starting point. There are unused icons in quill/assets/icons/ that can be helpful for tables. Implementing good UIs is non-trivial work but does not introduce any implementation design risk I can think of.
Let's see how far discussion in this thread can get us.
As an administrative note, I will delete all non-substantive comments from this thread to cut down the clutter and mass emails to everyone. Please use the Reaction feature to show support.
Embeds seem like the simplest solution, I like the approach to creating a table @jhchen laid out. One problem with this is pasted tables, which often come with a lot of formatting. We can assume people are using a reset style sheet that applies border-collapse:collapse and border-spacing:0; but all the attributes in the pasted table will need to then be stripped.
In the use cases I'm dealing with right now people really, really want to past tables from Word and Excel, which come with backgrounds and borders in inline styles.
Is there a way to strip these attributes without creating blots for td and td?
I've had some time to work on this today and I bumped into the issues @jhchen alluded to regarding formatting. Formatting cells with background colors as well as having contents with inline styles seems important. The trouble is making this work without a parallel api. Heres one way a table API with formatting could look:
insertEmbed(index,'table',[
[{
content:'Hello',
style: {
backgroundColor: 'red',
borderTop: '1px solid black',
color: 'white',
weight: 'bold'
}
},'World'],
['A', 'B']
]);
Resulting in:
<table>
<tbody>
<tr>
<td style="background:red;border-top:1px solid black;color:white;"><b>Hello</b></td>
<td>World</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
</tr>
</tbody>
</table>
Or are we getting to far into a world of parallel apis? Thoughts on this approach?
I'm trying to get some real data on our users that are currently pasting tables into CK Editor from word so I get a sense on what the "normal" interaction for pasted tables is.
I think a sensible "limited" table to emulate is tables in github markdown:
Hi, jhchen!
I would like to know when planning add support table.
Thanks
I posted a proof-of-concept Gist based on @saw's example, extending it to work with a React component that builds the table structure given some data. It works _okay_, but it's far from a complete implementation.
Yeah, it works ok, it has some limitations. I do want to finish this PR as
soon as I can, I've built more extensive table support for work, but our
use case right now is just pasting tables, not actually creating or editing
them.
On Thu, Oct 6, 2016 at 12:07 PM, Chris Cashwell [email protected]
wrote:
I posted a Gist
https://gist.github.com/ccashwell/e2ceac25d7195e4715a93587da89d747
based on @saw https://github.com/saw's example, extending it to work
with a React component that builds the table structure given some data. It
works _okay_.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/quilljs/quill/issues/117#issuecomment-252059016, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AABT5zr5uJpkgA0rIKH1oUoSJF96BCYBks5qxUbUgaJpZM4B9jc3
.
Would like to see this pretty please :) :+1:
I've also been working on adding tables to Quill and I think it's going quite well at the moment.
I'm using Quill as the heart of a collaborative editing experience in our app - multiple users editing the same stuff, like Google Docs. Quill has been awesome and has made this part of the application really clean.
So onto my tables. I did not like the embed approach, as it meant tables were really just a blob in the document, and editing the contents of a table cell was super limited with that approach.
Instead, I have approached the problem by treating tables in a similar was to lists in Quill. A ListItem is a node that lives inside a List and Quill handles this structured content well, creating the outer most <UL> when needed and adding <LI> elements inside it. I figured the same approach would work for tables. They are basically the same, but with a few extra layers 👍
So, I have a Table, a TableRow and a TableCell that all wrap the things below them.
The other benefit is that table cells can now contain any block level elements, like headings, lists, paragraphs, etc. All inline formatting works as well. They also work seamlessly with my collaborative editing features.
I'd say it has been a total nightmare getting the structure to remain sound, mostly due to my poor understanding of the internals of Parchment, but it is possible to add cells and rows and have everything correctly merged into place.
There is still a ton to do, but if anyone else has taken this approach, I'd be interested in talking.
Here is a quick screenshot of Quill, with tables, and someone else editing them...

Nice work @rikh42 ! We've been using the tables I created in production but I haven't had time to build the quill ui for it (we do not use the quill buttons but our own custom ui). The embed approach works, but to add features beyond "just tables" requires making more or less an entire parallel UI for tables. I spent a day or two going down the path you have but it was very complex and didn't seem realistic given our time constraints. Do you have your table format in a fork?
@saw I certainly learnt a lot by going over your PR a few times, so thanks for pioneering that!
It's in a branch of our internal project at the moment. It has turned out to be pretty complex, and I am sure there are still a few edge cases to figure out. (Well, there isn't a lot of code to get it working, but figuring out what the code should be, that was tricky :-)
I'm just working on all the keyboard handlers and UI components we'll need at the moment. My goal is to make something comparable to Tables in Google Docs.
Nice work @rikh42 ! What does a Delta look like for a document with a table?
Here is an extract from the middle of a larger document showing the first 3 columns in a table (JSON)...
There is some additional styling in there that you can ignore. who is a kind of authorship feature, but the bit you'll want to look at is the table-cell property. You'll see that they all have the same table and row id's as everything here belongs in a single table row in the same table. Additional blocks would just have the same cellId, and everything is resolved during insertion. No tbody or th at the moment, but I can live with that for now.
{
"insert": "Description",
"attributes": {
"who": 28167,
"bold": true
}
}, {
"insert": "\n",
"attributes": {
"who": 47194,
"align": "center",
"table-cell": {
"cellId": "table-cell-zxwscqtywssf",
"rowId": "table-row-oksghsnmwiwc",
"id": "table-id-tpbprwzxdlvn"
}
}
}, {
"insert": "Owner",
"attributes": {
"who": 28167
}
}, {
"insert": "\n",
"attributes": {
"who": 28167,
"table-cell": {
"cellId": "table-cell-epkzpvnrkoeu",
"rowId": "table-row-oksghsnmwiwc",
"id": "table-id-tpbprwzxdlvn"
}
}
}, {
"insert": "Cell 3",
"attributes": {
"who": 6939
}
}, {
"insert": "\n",
"attributes": {
"who": 28167,
"table-cell": {
"cellId": "table-cell-aerxfqxowhfd",
"rowId": "table-row-oksghsnmwiwc",
"id": "table-id-tpbprwzxdlvn"
}
}
}
Which results in the following HTML in the editor...
<table data-wrap-id="table-id-tpbprwzxdlvn">
<tr data-wrap-id="table-row-oksghsnmwiwc">
<td data-wrap-id="table-cell-zxwscqtywssf">
<p class="ql-align-center"><strong>Description</strong></p>
</td>
<td data-wrap-id="table-cell-epkzpvnrkoeu">
<p>Owner</p>
</td>
<td data-wrap-id="table-cell-aerxfqxowhfd">
<p>Cell 3</p>
</td>
</tr>
</table>
It would be nice to have a simple implementation of tables in the Quill. Really. I don't ask to give me something hard and serious — only basic support.
@rikh42 impressive work on table support! 🚀 Looks like there are many more that would like to play around with this, is it perhaps something or at least parts of it you could extract and share with the community?
I think I have an idea of how @rikh42 implemented it. I tried to hack my implementation based on the list and list-item blots. Lets say we are implementing 3 new blots: table, table-row, table-cell. The main differences from the way the list is implemented are:
format on the level of the outermost container (in lists the ul and ol are responsible for the format, not the li), we have to work with the format on the level of the inner-most container (table-cell).list -- we create the outermost container. For example, when you initially render 10 list items, quill actually renders each list item in a separate ul, and then it creates defaultChild item within each ul.optimize() function fires for each ul and it ends up moving all li items into the first ul.table-cell), we need its optimize() to also do some work by first wrapping itself into table-row. Then table-row's optimize() needs to wrap itself into table.table-cell then the table-cell should also be a Container and we need to patch Block and probably List to be aware of the table logic and to be able to wrap itself into table-cell (which then wraps itself into table-row, which then wraps itself into table)Well, that's what my current thoughts are, I don't actually have a working solution yet, so it would be really nice to hear from @rikh42 or anyone else hacking this feature.
I agree @rikh42 has the right idea, but it's very tricky, I would love to
see their code to understand how they made it happen
On Mon, Jan 30, 2017 at 6:20 AM Pavel Zhukov notifications@github.com
wrote:
I think I have an idea of how @rikh42 https://github.com/rikh42
implemented it. I tried to hack my implementation based on the list and
list-item blots. Lets say we are implementing 3 new blots: table,
table-row, table-cell. The main differences from the way the list is
implemented are:
- Instead of working with format on the level of the outermost
container (in lists the ul and ol are responsible for the format, not
the li), we have to work with the format on the level of the
inner-most container (table-cell).- When we create a list -- we create the outermost container. For
example, when you initially render 10 list items, quill actually renders
each list item in a separate ul, and then it creates defaultChild item
within each ul.
Then the optimize() function fires for each ul and it ends up moving
all li items into the first ul.
But since in the tables we create the inner-most container (table-cell),
we need its optimize() to also do some work by first wrapping itself
into table-row. Then table-row's optimize() needs to wrap itself into
table.- And that's not it! If we want to have paragraphs and lists inside
table-cell then the table-cell should also be a Container and we need
to patch Block and probably List to be aware of the table logic and to
be able to wrap itself into table-cell (which then wraps itself into
table-row, which then wraps itself into table)Well, that's what my current thoughts are, I don't actually have a working
solution yet, so it would be really nice to hear from @rikh42
https://github.com/rikh42 or anyone else hacking this feature.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/quilljs/quill/issues/117#issuecomment-276073767, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AABT5x9FUOm1XeuFJxwGbTotm6kOwH_dks5rXfG7gaJpZM4B9jc3
.
@cray0000 in that approach how do you determine what <td> belong to which <tr>? It seems if you work up from a the cell you have no way to determine when to wrap in <tr> that matches the defined table during the value() phase, unless I am not seeing it.
@saw,
table-cell will have ids for <tr> and for <table>. And if we want to have lists and paragraphs within td then we also need the id for td too). But for now lets take the simple case of 2 ids -- row and table
Actually the tableId is optional, depends on whether we want 2 separate tables to automerge together or not. For example list does automatically merge together with the list next to it. If you have 2 of them separated by <p> and you remove that <p> -- then those 2 lists will be merged into one. The same is true for the table implementation. If we take into consideration tableId, then 2 separate tables can exist next to each other. Otherwise they will be always merged into a single table (even though the amount of columns may not be equal).
So lets say we want both rowId and tableId and we don't want <p>/<li> within <td>. Here is my suggested algorithm (I didn't actually test it, it's just an idea):
table-celltable-cell with the value of { rowId: 'aaa', tableId: 'bbb' }static create() and static formats() to attributes data-table-id, data-row-id.optimize() we check whether the parent is table-row. If not -- we wrap it into table-row by creating that blot and passing it the same value -- Parchment.create('table-row', this.statics.formats(this.domNode))table-rowHere is where the merging of <tr>s is going to happen (moving <td> into a single <tr> they belong to).
table-row will be created by its child (table-cell) with the same value. static create() and static formats() will set data-table-id, data-row-idoptimize() will do 2 things:
a) merge sibling table-rows together by data-row-id -- this is done the same way as currently in list:
if (next != null && next.prev === this &&
next.statics.blotName === this.statics.blotName &&
next.domNode.getAttribute('data-row-id') === this.domNode.getAttribute('data-row-id')
) {
// move stuff from one <tr> to another, the same as in 'list':
next.moveChildren(this);
next.remove();
}
b) check whether the parent is table. If not -- we wrap it into table while passing the same value to Parchment.create.
tableThe table blot is basically the same as table-row but it's not interested in rowId anymore and only cares about the tableId and the corresponding attribute data-table-id. And it has the same optimize() as table-row which merges tables together based on the data-table-id attribute, but since the table blot is the highest level we don't need to wrap it into anything.
I think <thead><th></th>...</thead> will need some love in all this. Some people will want to use this sort of thing against GFM.
@rikh42 I'm pretty sure you'd be a hero to the Quill community if you open sourced the code for your table implementation (even if it's not something that's mergeable back into Quill right now).
I know I'd be happy to work on it in the open, and it sounds like you'd have plenty of other people willing to help out!
Hey @cray0000 do you mind posting any code that you've been hacking on related to this? I'm also working on it, but my experience with Quill is still quite limited, so having some reference code to compare my work with would be very helpful.
@2Pacalypse- I didn't have time to actually start seriously hacking it yet.
The only implementation I have right now is a pretty silly one with just the trs and tds as custom tags with flex layout -- implemented in exactly the same way as quill's list and list-item.
Here it is: https://gist.github.com/cray0000/9e9eeca6a6ce292453a09ddf6c0c4ad1
I plan to get to the coding of the real table/tr/td sometime this week. As soon as I have it working (or when I at least have some part of it working) I'll open source it right away -- as a gist or as a quill plugin.
Thanks!
I've been following your design outline that you wrote above and I think that's a good way to structure the code. However, there are a couple of things that needs clearing up. What should be the blot types of table, table-row and table-cell formats? In my code, I've made table extend the Container blot (same as list), table-row extends the Block blot and table-cell also extends a Block blot. I've tried making both the table and table-row a Container blots, but bad things happened :d.
Another thing that I'm still trying to decide is how to insert an initial table. Most text editors allow you to specify on the toolbar the number of columns and rows you want and then the table of those dimensions is created. I wanted to do something similar in my code (for now I'm just hardcoding the number of columns and rows, but later on will focus on creating some nice popup for handling the tables).
And the last thing which I'd really like if someone can clear up for me is which methods exactly do we need to override in our table blots to make the tables functional. Only create, formats and optimize? Is there some set of methods you _need_ to override to achieve a specific functionality? Parchment's docs are kinda hazy on this.
Again, thanks for your help. I'd really like if we could collaborate on this to make the table support in Quill a very near reality! ^^
2 cents on the overall idea: i support that having TD's based on actual text rows is a right way, but thinking one step further - there's more work for collaborative environment. For example, common problem to solve is - two persons editing document at the same time, first inserts row, second inserts column. The OT implementation should be aware of tables to handle this properly, for ex. there should be special operation like "insert row at line X" that will behind the scenes will insert proper number of 'n' with TD attributes at specified location, instead of just multiple insert operations. Since i'm very new to Quill, i'm still researching how Delta generation works and if it's possible to have proper Delta representation that will help handling this.
@dmitryuv I think for any Table solution to be considered complete (and think about being folded into Quill core) @jhchen (and correct me if i'm wrong) is likely going to be able to want a Table solution where you can do:
let contents = this.quill.getContents()
this.quill.setContents(contents)
And have the document look exactly the same.
In addition to the above constraint, you will likely have to be able call compose and transform without the Table being completely overwritten by any one change. Meaning User A should be able to enter text in Row 1, Column 1, and User B should be able to insert text in Row 1, Column 2, simultaneously, and the transform or compose operations on the Delta should correctly insert both changes.
@danielschwartz that's all achievable with proposed solution as cell content is technically equal to list item, with different outside wrap. But it won't survive transform("insert column" against "insert row") operation without special table-aware logic. That's my point :)
Let's assume it's possible for a user to select in the toolbar that they want to insert an empty table with N columns and M rows. Can we try to figure out how this could/should be done with the existing API.
Something like this maybe?
// Assume this is the handler that gets called when a user clicks 'Create table' in the toolbar
const insertTable = (columns, rows) => {
const tableId = 'bbb'
for (let i = 0; i < rows; i++) {
const rowId = i + '-aaa'
for (let j = 0; j < columns; j++) {
quill.format('table-cell', { rowId, tableId }, Quill.sources.USER)
}
}
}
Then @cray0000's design takes effect and each cell wraps itself in appropriate row, and row into a table. Feedback is welcome.
@2Pacalypse- I don't think this is going to work -- it'll probably just rewrite the same block item many times over and over again, trying to change the formatting of the same block item where you currently have your selection.
I think the solution here depends on whether we want for whatever was already selected to end up within the top left cell or not.
If we want that -- we need to use quill.format() once. And all the other cells need to be inserted after the closest \n to the right directly via the delta operations by doing quill.updateContents().
Or if we don't care about the selected text and just want to add table after the selection (possibly splitting the current block) -- we should just do the quill.updateContents() right away.
I'd vote for just putting the table after the current selection. In which case the code can look something like this:
import Quill from 'quill'
const Delta = Quill.import('delta')
// suppose we have `this.quill`
addTable (columns, rows) {
let range = this.quill.getSelection()
if (!range) return
let tableId = 'table-' + Math.random().toString(36).slice(2) // dirty random id
let changeDelta = new Delta().retain(range.index + range.length)
for (let i = 0; i < rows; i++) {
let rowId = 'row-' + Math.random().toString(36).slice(2) // dirty random id
for (let j = 0; j < columns; j++) {
changeDelta = changeDelta.insert('\n', { 'table-cell': {rowId, tableId} })
}
}
this.quill.updateContents(changeDelta, Quill.sources.USER)
}
@2Pacalypse- On the second thought though, the ideal behaviour would probably be to insert the empty table on the next line (after the nearest \n to the right of the current selection):
import Quill from 'quill'
const Delta = Quill.import('delta')
addTable (columns, rows) {
let range = this.quill.getSelection()
if (!range) return
let newLineIndex = this.getClosestNewLineIndex(range.index + range.length)
let changeDelta = new Delta().retain(newLineIndex + 1)
let tableId = 'table-' + Math.random().toString(36).slice(2)
for (let i = 0; i < rows; i++) {
let rowId = 'row-' + Math.random().toString(36).slice(2)
for (let j = 0; j < columns; j++) {
changeDelta = changeDelta.insert('\n', { 'table-cell': {rowId, tableId} })
}
}
this.quill.updateContents(changeDelta, Quill.sources.USER)
}
getClosestNewLineIndex (index) {
return index + this.quill.getContents()
.map((op) => typeof op.insert === 'string' ? op.insert : ' ')
.join('')
.slice(index)
.indexOf('\n')
}
Thanks a lot for the feedback. I'm still very new to the Quill, so any help is appreciated ^^. I think I understand how that code can work, although shouldn't this line actually insert table cells instead of a new line?
changeDelta = changeDelta.insert('\n', { rowId, tableId })Something like this perhaps:
changeDelta = changeDelta.insert({ 'table-cell': { tableId, rowId } })
When I do that in my code, it actually works and it inserts a correct number of table cells in the editor. But this is the part where I struggle with Quill's internals a bit, to make sure each table-cell properly wraps itself into a table-row parent. Any ideas on what's the best way to achieve that?
@2Pacalypse- oh, you are right, I forgot table-cell. But you still need to insert the new line. Since the table cell is the block element, the same as list. And all block elements in Quill are marked with the new lines.
So it should be:
changeDelta = changeDelta.insert('\n', { 'table-cell': { tableId, rowId } })
And actually another thing which needs to also be addressed is that only having tableId and rowId won't allow us to have lists or several paragraphs within the table cell.
If we want to be able to press Enter within a table cell to create a new paragraph, then we should actually add another ID -- cellId. And we need to overload Block's optimize() (and possibly ListItem) to support wrapping themselves into the table-cell -- the same way as table-cell wraps itself into table-row.
Yeah, that makes sense.
I'm struggling a bit on writing the code which should wrap table-cell into the table-row. I've managed to create a parent table-row element and correctly set its children to the appropriate table-cell elements. But this is all on the level of the Parchment's document model. Not sure how to apply that to the actual DOM as well.
We would also like to help with adding tables to quill for our project.
Following discussion here by @cray0000, @2Pacalypse- and @rikh42 we kicked out this solution so far: https://github.com/dost/quilljs-table
Since it actually generates tables, html code and delta well, it looks like good start so we would like you all and some day even @jhchen to look at it and help us to put it all together :)
Thanks to you all for code and inspiration...
Nice!
Will go over your code and see if there's anything I can help with :)
there is live demo on server for quick preview: http://quilljstable.timepress.cz/quilljs-extended-toolbar/contain.html
Hey @cray0000, could you please clarify this part a bit more:
If we want to be able to press Enter within a table cell to create a new paragraph, then we should actually add another ID -- cellId. And we need to overload Block's optimize() (and possibly ListItem) to support wrapping themselves into the table-cell -- the same way as table-cell wraps itself into table-row.
What would the condition be to check if a Block blot should wrap itself into table-cell?
Also, do you (or anyone else) might have an idea what can cause this error:
Uncaught Error: diff() called with non-document
It happens when a delta operation doesn't have an insert property in certain cases, but not sure what those cases are exactly.
One last question (for now ^^):
Why does quill.getLeaf() method returns a TableCell blot even though when I inspect that blot, it has a Break child. Shouldn't the quill.getLeaf() method return the actual leaf at the particular index, which in this case would be the Break blot?
@2Pacalypse- to answer your question about the diff() error. Basically, when you call a.diff(b) both a and b must be Quill delta's that only include inserts. This is where the error gets thrown.
We moved forward our work on tables: test editor
It does:
If you have a time to look at it, you will find all code for tables in quilljs-extended-toolbar subdirectory of project. It is just one JS file and one HTML file.
Public repo is at: https://github.com/dost/quilljs-table.
Your input is highly appreciated.
I also made my own version of the tables support. You can see the demo here: http://galaxy.fesb.hr/quill/index.html
Source can be found here: https://github.com/2Pacalypse-/quill
For now it inserts a default 3x2 table, with the ability to insert new rows before the one currently selected and it's also possible to insert new columns to the left of the one currently selected. The plan is to work on a better toolbar support for working with tables next. Few notable things that are missing and will hopefully be added soon:
@2Pacalypse- that's pretty clever way, great job! Regarding your question in the code - i don't think merging tables is a good idea, people might not want this to happen especially if there's no way to "unmerge" them. One thought - having all 3 attributes with repeatable values seems excessive, do you think it's possible to roll them up into just plain 3 (cell, row, table)?
@dost That's a pretty clean table editor. Most of my suggestions are seen within your "Known Issues" on the repo. I think it should also be able to delete a row, or delete a column at the click of a button. I'm pretty interested to see it take off.
@dmitryuv
Regarding your question in the code - i don't think merging tables is a good idea, people might not want this to happen especially if there's no way to "unmerge" them.
Yeah, will probably take that out for now. But I do think that in future it might be useful to have an option to merge two tables together (and of course be able to unmerge/undo it).
One thought - having all 3 attributes with repeatable values seems excessive, do you think it's possible to roll them up into just plain 3 (cell, row, table)?
This is something I was wondering about as well. I was hoping that someone with more experience with Quill and Delta internals would be able to shed some light on. It feels with the approach I took (which is actually @cray0000's approach outlined above ^^), it would be pretty hard to do since we have 3 separate blots all being inserted. And each of them _needs_ to have a way to be able to say where they belong, eg. a cell needs to know which row and table it belongs to.
The way it is now makes it pretty easy to get rowId and tableId for each cell, but thinking about it further, I guess we could make the delta a bit more succinct by only making each blot have their respective id. So it would look something like this:
{
"attributes": {
"table-cell": {
"cellId": "cell-oi1sibyxp4dbl3a1j8v5kx1or"
},
"table-row": {
"rowId": "row-e6jj7821yfms4fn0topskmx6r"
},
"table": {
"tableId": "table-mbgxs12ydrji1bpv1ujl9pb9"
}
},
"insert": "\n"
}
This way, each time you need to get tableId for a particular cell, you would need to do cell.parent.parent and then get the tableId from the table blot. But yeah, I think that's actually the better way to do it and having the delta be as optimal as possible is very important. Thanks for the feedback!
Here’s an approach that doesn’t require generating IDs, but instead uses embeds for row and cell “breaks” to identify TRs and TDs that need to be rendered as separate elements.
http://jsbin.com/defixum/edit?js,output
The advantage here is that you don’t have mess with ID book-keeping at all.
Conceptually, the structure of a table delta is
insert "Row 1 Col 1"
insert "\n", attributes: { td:true }
insert { tdbr: true }
insert "Row 1 Col 2"
insert "\n", attributes: { td:true }
insert { trbr: true }
insert "Row 2 Col 1"
insert "\n", attributes: { td:true }
insert { tdbr: true }
insert "Row 2 Col 2"
insert "\n", attributes: { td:true }
insert { trbr: true }
Caveats:
It has decent parity with https://github.com/dost/quilljs-table in terms of features and open issues, except that it doesn’t do nested tables as you can do when using explicit table IDs
@WinstonFassett i like it, in my case i don't need nested tables so easier solution is preferable. I'd add problems with lists to the issues, but overall looks good. Do you plan to keep working on this?
Thanks @dmitryuv,
I will look into the list issues. I did try pasting a list into a cell and it worked but had problems on enter, so perhaps the issue can be fixed with keyboard handlers.
This isn't for my day job and I'm still proving out the approach, so I hesitate to publish in anything more formal than gists/jsbins. However, I'm pretty committed to quill in my side project and am keen on this feature, so I will keep moving it forward as time permits until I settle on an implementation.
I think I got lists working, although I had to make a small change to bubbleFormats in Quill.js so that attribute ordering is preserved in a top-down manner.
Updated demo: http://jsbin.com/defixum/6/edit?js,output
The attribute ordering matters when you have a block that is both a td and a list. Things work as expected if the td attribute is first. However, the current implementation of bubbleFormats appends things bottom up, so that the TD is always last.
Changing from extend(formats, blot.formats()) to extend(blot.formats(), formats) seemed to fix most of the issues with lists in tables without making any changes to the actual table code.
This might also fix the same list issue in quilljs-table.
啊啊啊,我可以说中文么?
是不是只支持拷贝一个表格过来可以让事情变得简单一点。
这就满足了楼主一旦创建后就不改变的要求。
这样,很多用户的问题就有了个临时解决方案,很多人会很开心!!!
Let me try some english ,
The first step ,support copying a table from another page ,maybe it make things simple.
jhchen commented on Sep 4, 2016 • edited :"Tables cannot be resized after creation" ,I think it is right .
We can edit a table by using another edit tool ,and then copy the table into the quill ,
We can modify the table again If need ,and now, we have the table ,
and have the time to discuss the more cormfortable solution.
Hi! 🙂 @WinstonFassett you made fantastic progress on the Quill-JS table feature. 💯 🥇
Did you further continue on your implementation? 🙂 Could I somehow help within a Git-Repository? because I really like your approach and would like to make an impact 🙂 Above you mentioned, undoing table commands sometimes have messy results. I'm eager to make that work!
Thank you so much, you started something amazing! 🥇 👏
Impressive work I've seen so far from everyone on the Quill Table support. Is it safe to assume this will not come out of the box from the development team? Last repo I saw was updated 5 months ago now.
Not sure which repo is being referred to but Quill was updated 4 days ago. But no Quill does plan to add official table support in the future. There is no timeline at the moment but the community can make it faster by contributing and exploring implementation designs which is what is being done here.
@jhchen I think @Theopt is referring to the repos discussed in this thread, work on tables seems to have come to a halt and the solutions here are too half baked to use in production. I do agree that there needs to be more contribution and discussion but IMHO work needs to be done to the core features to make it easier to develop features like tables... there seems to be a reluctance to accept things are actually needed.... maybe we can start with figuring out the roadblocks that preventing this particular feature from moving forward?
I have been working with the quill.js platform for about 2 months, I'm not the greatest coder in the world but have been one for over 20 years, I've read through the quill.js, delta and parchment codebases and I still have trouble with most of my extension efforts... in particular the lack of support for nested blocks(and deltas) and the handling of breaks to be particularly troublesome.... when I originally investigated solutions based on quill.js I was lead to believe extensions would be straightforward, looking at a lot of community code, it's alarming how much of it is incomplete... a lot of devs seem to drop support for the delta format and just use html, which is obviously a step backwards....
There is definitely an issue with guides, the medium guide is good but we need more guides for more complex things involving parchment and delta.... I know guides/docs are on the roadmap, there are apparently no plans for table support, I hope there are plans to make developing tables easier because nobody seems to be having any success with this (solutions are incomplete, and not actively being worked on, there isn't very much community code out there considering this is supposed to be an API driven application). I appreciate everyone's hard work and I hope quill.js has a bright future, as long as I'm working with it, I will help wherever I can but I would like to see some light with several features that have been talked about for several years now.
@seandearnaley That was exactly what I meant back there. I hope you guys make it because it is so much lighter and easy to use than everything else I've found so far, and to be honest all I need to use it in production is the tables part now : ) Unfortunately I'm trying to replace some parts of a legacy product and I'm on a time schedule. Most likely be using CKEditor for this rollout. Will keep an eye on Quill for sure.
Tables are a very large feature that will take time and work to add. I have posted a very detailed suggestion on how to start and proceed. If you want to ignore this advice that if your prerogative but the expectation it should be easy or straightforward to add tables from zero represents a gross misunderstanding of the feature.
Alternatively you can just wait for us to add it in core but either way unconstructive complaints are not helpful.
I added on some functionality to @WinstonFassett's work on tables.
Here it is in a repo. Just open the body.html to load.
So much thanks to @WinstonFassett because without his work on the actual Parchment objects and low level stuff I wouldn't have been able to add my UI aspects.
I added tab functionality inside tables, so if you're in a cell it'll go to the next one and vice versa for shift+tab. If you're in the last cell of the table and hit tab it'll add a row, so that's fun. The only time it doesn't go to the next cell is when you're in the very first index of the first cell. This is mostly l likely due to my algorithm for finding the next td.
Also added some css to make the table cell's equal width. This is for my planned update where I add some ability to resize akin to Word and Google Docs.
I also made the <p>'s inside table cells vertical-align: top because it made more sense, imo. Feel free to change it.
Most work could be done to the functions to improve them/clean them up. Outside of that from a potential PR perspective lots of work needs to go into figuring out how exactly to make tables work with the stack. undo/redo doesn't work at all really. Redo'ing a row add creates a new table entirely.
Hi all, what do you think about an modal/dialog to edit a table that becomes inserted as a embeded? If you click into the table within quilljs the dialog gehts open to make content and table/cell property changes? In this way we dont need to enforce quilljs to support table-editing within its canvas. And on the other hand the dialog-table-tool could be an opensource project of its own like https://limonte.github.io/sweetalert2/ with a api with events to pass data onOpen and sends/returns data back onClose.
Great work so far, the last version I looked at from @WinstonFassett seemed pretty damn good to me.
Moving forward I think the Resize-module from kensnyder's image-resize plugin could be useful. The idea of overlay controls inside the editor is also something that could come in handy for adding cols/rows or opening up a settings modal.
https://run.plnkr.co/k0LyTIn6BfFLuemu/

The company I work for is using Quill on one of our projects. The table support will be a great improvement for it!
Is there a planned date for 2.0 release?
@lucassoamaral you can read about Quill 2.0 here.
I need this feature so badly that I'm going to start working on it, but reading the article that @benbro pointed out I see that table support is coming in version 2, which leaves me with further questions:
I need this feature for my work, so I will be working on supporting tables either on my own branch or collaborating with other developers (probably I will be checking out other repositories to see what has been developed so far), any suggestions or guidance?
Personally I like how summernote handles tables, so I am going to implement something similar.
Maybe tell this to potential users immediately on YOUR FRONT PAGE. It took me hours to replace my old editor with Quill.... it looked very promising. And suddenly... you see... no table support?????????? Come on, guys????
I’ve been an avid Quill user for years at this point, and have been following this thread for a while. Table support is important, we all know it, we’ve all been clamoring for it, and yes sometimes it’s been frustrating that it’s not officially supported yet.
However, @KrisMerckx, please rethink your approach to open source projects and how you interface with the implementing team. @jchen and the rest of the contributors of this fine project owe you absolutely nothing, and the fact that we get such an amazing and extensible editor that “just works” out of the box, is nothing short of astounding. No one made you choose Quill. No one made you skip over the Formats section of the website. And certainly no one made you spend hours implementing it without reading the docs thoroughly. It’s replies like yours that make people rethink open sourcing things.
@jhchen and the rest of the contributing team: _You make an amazing piece of software._ Just know that there are lots of folks (like myself) who love this project, and appreciate all of the effort and work you put into it.
And if you’re ever in NYC, there’s a round of beers for y’all on me 🍻
@javiercbk check out my work with some of the UI for tables. Github. I was struggling with the Parchment/DOM based interactions and coding, but I was able to figure out some stuff for navigating them as a user.
Hey @jhchen, I've seen this commit you made a while back. I'm using a similar approach.
Would care to comment on that? Is that a good idea?
I'm using another this repo and creating tables in a similar fashion. Any comment on that?
Thanks
EDIT: In on of @jhchen comments he says that he posted something about how to implement tables. Does anybody knows where that post is?
EDIT 2: I'm also taking a look at @2Pacalypse- work
@javiercbk I think that was something I tried and decided against. I don't remember the reason. This comment is what you are looking for. Subsequent comments by others who tried this approach or took a different one are also useful.
@jhchen I think the biggest issue with lack of table support for us is the formatting not being preserved when pasting in content. For example, pasting in a user's email signature with their name on the left, and their logo on the right and a border in between.
Just fixing the pasting issue (and allowing tables in the dom) would be a huge win, versus adding support to insert a new table from the toolbar, etc.
Keep up the good work!
Great work on this so far guys, can i in some way contribute to speed up the release of this feature ?
I have implemented support of tables using multiple bloats approach. Tables stay consistent after quill.getContents() : delta -> quill.setContents(delta).
I'd appreciate any feedback: https://github.com/unstoo/cpay-wysiwyg/blob/master/src-client/TableBlot.js
The only question I have is regarding pasteHTML of a table. It parses a <table> down to a funny looking delta[ops]. Would the clipboard module be the right place for fixing tables parsing behaviour or should I look elsewhere @jhchen?
Also, can you give me a hint how do I go about disabling enter hits from inserting anything into a table?
I've tried to add a blank handler to the bindings module, but as a result the behaviour of enter strokes becomes inconsistent.
key: 'enter',
format: ['table'],
handler: function(range, context) {
return false
}
just want to know that when will version 2 publish? I need table support recently. ths~
The long awaited table support is almost here! You can check out a demo with the latest 2.0 dev build here: https://codepen.io/quill/pen/QxypzX. The UI is not polished of course but the functionality is there. Having multiple editors on the page is meant to test the API and all changes from one should be perfectly produced in the other. I'll be filling out the 2.0 upgrade guide in the next week or two so you can try out tables in your own applications soon. The full 2.0 release will be further out but the dev build is meant to be well documented enough for the brave and eager to try.
In the meantime, help testing and reporting bugs in the demo would be greatly appreciated. Please comment with the bug report (must include your browser/os, steps for reproduction, expected and actual behavior -- there would be too much noise from back and forth otherwise).
The supported features tables features/limitations include:
I will not discuss including additional features here. Please open a separate feature request to request this.
As an administrative note, have marked existing comments as outdated and will also continue to delete all non-substantive comments from this thread to cut down the clutter and mass emails to everyone. Please use the Reaction feature to show support instead of commenting.
great work and happy to see tables are making it into editor core!
Chrome 67 / Mac OS High Sierra
1) Insert table, put cursor into first cell on first row, type and hit Enter. Result: new row inserted BEFORE table. Expected: row should be inserted within cell
2) Insert table, put cursor into first cell on second row, type and hit Enter. Result: new row inserted AFTER table. Expected: row should be inserted within cell
3) Insert table, put cursor into any cell, type then hit Shift+Enter. Result: new cell inserted into the same row on the right, table broken. Expected: row should be inserted within cell.
Thanks for the notes @dmitryuv. I've fixed 3 and updated the codepen with the new dev build however the expected behavior around the first and last row is inserting a newline outside of the table. Otherwise a table at the edges of the document would prevent any entry before/after it. Also this tables implementation does not allow newlines inside cells. Feel free to open a separate feature request for this.
@jhchen thanks for the update. I see you point regarding newlines, however it's a bit unexpected behaviour comparing to other products. I would agree on having Enter to move cursor below table, but naturally hitting "Enter" after filling column on the first row results in bad UX.
Solution? Right now if you create new row above table, there's no way later to remove it (try yourself). Could it be a solution if you automatically create the same editor state when first inserting table into the topmost position?
Regarding multiline - i think this should be fundamental decision and not a separate feature request. For example if you decide to NOT support it, all line-based formats should be automatically disabled once you're in a table. Also any copy&paste should be properly sanitized
Bug or not-fixable?: You can create wrapped line by typing too many text, but it's hard to navigate it for edit. "Down" key moves you to the cell below instead of one wrapped line below. I've seen such behaviours in other editors before if navigation on wrapped text is not explicitly supported.
Bug or intent?: if you apply any row-level format to the cell, it breaks table into separate tables. Any combination of copy&paste of selection that includes tables and row formats create unexpected results. I could get the pattern after few samples but for end user that could be unexpected.
However, if split table behaviour is by design, i can see it might be a good enough solution with proper UX feedback.
I should clarify the supported features (which I'll edit my original comment for visibility).
These decisions have been made deliberately with consideration of many factors but the biggest is the complexity (both implementation and UX) to utility ratio.
The unable to delete the row above/below the table has been fixed in the develop branch.
I had to overwrite up/down because the native behavior is advancing to the next cell (not the next row) which I thought was unexpected. I did not consider wrapped text though. It would probably have to be one or the other but maybe the next cell is not so strange.
It should also be said Quill is built for customization and all of the keyboard interactions can be changed or removed.
At this point as well I am most concerned about correctness and robustness.
@jhchen Great work on tables, there were some table layouts which I don't think are valid as per current description. Sharing details for them.
Browser: Chrome Version 67.0.3396.87 (Official Build) (64-bit)
OS: Linux(Ubuntu 16.04)
Inconsistencies in table layout.
1. Insert Table
2. Insert Row Above
3. Insert Column Left
4. Delete Row
5. Insert Table

Some other outputs. Repro steps not available for below cases

Bubble Delta
{
"ops": [
{
"attributes": {
"table": "row-dpl2"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-vtlg"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-7bij"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-w7z7"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-b1pp"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-7bij"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-b9gy"
},
"insert": "\n\n\n"
},
{
"insert": "\n"
}
]
}
Snow Themed Editor Delta
{
"ops": [
{
"attributes": {
"table": "row-dpl2"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-vtlg"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-7bij"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-w7z7"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-b1pp"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-7bij"
},
"insert": "\n\n\n"
},
{
"attributes": {
"table": "row-b9gy"
},
"insert": "\n\n\n"
},
{
"insert": "\n"
}
]
}

{
"ops": [
{
"attributes": {
"table": "row-o4bv"
},
"insert": "\n\n\n\n\n"
},
{
"attributes": {
"table": "row-2yy5"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-mb38"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-ye3v"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-bafm"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-omgi"
},
"insert": "\n\n\n\n\n"
},
{
"attributes": {
"table": "row-sx8i"
},
"insert": "\n\n\n\n\n"
},
{
"insert": "\n"
}
]
}
{
"ops": [
{
"attributes": {
"table": "row-o4bv"
},
"insert": "\n\n\n\n\n"
},
{
"attributes": {
"table": "row-2yy5"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-mb38"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-ye3v"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-bafm"
},
"insert": "\n\n"
},
{
"attributes": {
"table": "row-omgi"
},
"insert": "\n\n\n\n\n"
},
{
"attributes": {
"table": "row-sx8i"
},
"insert": "\n\n\n\n\n"
},
{
"insert": "\n"
}
]
}
Thanks @saralnigam -- should be fixed now and updated the demo
Who can say how to use it with npm and React?
@KindBear v2.0 isn't available on npm yet. You've to wait until it officially release to the npm or use dev build at your own risk from https://cdn.quilljs.com/2.0.0-dev.2/quill.js.
You can do npm install [email protected] but yes use at your own risk.
Hi @jhchen,
We are looking forward to the release of v2 and the ability to use tables ✨
Do you have a (rough) eta on when it will be there?
If you (force) feed an editor a table within a table by manipulating myQuill.root.innerHTML, it doesn't like it.
<table>
<tr>
<td>
<table>
<tr>
<td>
A table within a table fails.
</td>
</tr>
</table>
</td>
</tr>
</table>
Otherwise, force feeding works well and I am _very_ excited about the prospects of using tables with Quill. Tables are big part of HTML. Thank you for your hard work, let us know when you're done!
pasteHTML was deprecated in favor of dangerouslyPasteHTML and now removed in 2.0. Please keep this thread to table stuff only as you are notifying dozens of people. As I stated above I will remove irrelevant comments.
I tried to use the quill-table module, but I want to use the built-in module. How do I add options for the toolbar? I could not find how
Is colspan/rowspan support in the pipeline?
Hey hello,
First of all thank you for developing quill.js, it's a great library.
At the moment I am using the https://cdn.quilljs.com/2.0.0-dev.2/quill.js as I need the table support. It works well so far but I have another question: is it possible to graphically resize the columns by any chance?
Thank you very much
Simo
The current dev version posted uses a lot of lambda functions, can there be a transpiled version uploaded? Current version does not support IE :(
Hi everyone,
For some time now I have been experimenting with Quilljs and I think it works like a charm. For my usecase of the Quill editor I'm in need of the table module that is still in the development branch. Now I was wondering if there is any estimate on when this is going to be officially released. A release window would already be very helpfull. If there is a place where I can find the schedule for the quill editor it would be great if someone could point me in the right direction. If the release of the table module is not somewhere in the near future, is it possible to only add the table module from the development branch or do I have to adopt the development branch as a whole? I'm excited to see what's comming to quill in the future.
In any case, thanks in advance and great work on Quill,
Jeroen
hello @jhchen ,
how can i add table feature to toolbar using toolbarOptions,
not as external buttons as specified in the demo
https://codepen.io/quill/pen/QxypzX
Table support is a great addon to the already great features of Quill :) If/when the tables are supported, does this mean the user could paste a copied table from Excel? This is a feature many of so called "standard users" have asked. People seem to think that if the data is in Excel it can be copied anywhere without losing any of the formatting :/
Replying to myself :) Copy - Paste from Excel seems to work, meaning that the cells and data are kept in their correct places. Great! :) However, pasting the table looses the borders. Is this something easily fixable? Is there a way to define table border in Quill currently?
@olliraa can you please share with us the code, to know how to implement table feature.
Just curious, is this going to be an IE feature? Or is IE being deprecated out as of 2.0?
@JeffHerb , why would IE become deprecated? As far as I know, it has decent support for tables and contentEditable, at least starting with IE 8 and above.
Hi @jhchen, first of all I would like to thank you for making quill available for community. I am currently using quill 1.3 with tables and trying to merge selected cells. I am fully aware that this feature is not supported, as you mentioned earlier.
What I am interested in, is your insights on how this feature could be implemented. Specificaly, how could I keep value of selected cells and/or how to get value of last cell in selected table.
@earshinov, just curious because the IE support does not exist for the alpha/beta tables plugin.
@vikvet Just to clarify, it sounds like you were able to back-port the Quill 2.0 tables implementation to work with Quill 1.3?
Replying to myself :) Copy - Paste from Excel seems to work, meaning that the cells and data are kept in their correct places. Great! :) However, pasting the table looses the borders. Is this something easily fixable? Is there a way to define table border in Quill currently?
I did it by creating a CSS rule:
.ql-editor table tbody td {
border: 1px solid black;
}
Can anyone please tell us what is the timeline for 2.0 prod version with tables?
@sachinrekhi Hi using Quill in Agular 6 project with ngx-tables, which i belive run only on quill 1.0. Few modification has been made. Without mergin cell at least on same tr is the table plugin not really useful.
Also need of table_id, row_id,.. is not fully understood by me, i can see that it has something to do with html sanitation, as quill make p tag fromeverything he does not know, including already existing tables(those created without quill thus no id's) which is odd as table is basic html. My knowlege of Quill is limited and answers might be available online, and i just did not find them.
const td = this.find_td('td');
td.domNode.nextSibling.remove(); Seems to remove next cell, but the changes do not persist in DOM
JS remove methods dont work.
update: const td = this.find_td('td');
const table = td.next;
table.remove(td);
Hi, @jhchen. I really like the extensibility of Quill a lot.
I implement a module quill-better-table to add support for tables.
Online demo is here: quill-better-table demo
Hope that quill-better-table could help someone who need to edit/render table in quilljs.
Requirements: quill.js v2.0.0-dev.3
is there a way to render a table in a table for quill editor?
I implemented a module for basic table UI
https://github.com/volser/quill-table-ui
it provides a dropdown for table operations.

Just adding a note to anyone who's googling about tables to say 2.0.0-dev.3's built in table functionality is nowhere near production ready so I wouldn't use it on a production product. I'm aware this stuff is mentioned in other issues but it should be aggregated
What I've observed so far:
There's a plugin called quill-better-table (referenced above) which provides a lot of the table features you may be looking for. Some things still break (eg. lists within tables) but it's an admirable effort from one person and much closer to what you'd expect from a table module; unfortunately it requires quill v2 so that may be a deal-breaker.
On the whole if you haven't yet adopted quill and tables are important to your project, I'd strongly consider alternative editors (e.g. ProseMirror, TinyMCE)
Hi @jhchen do we know when is the release of quill 2.0 version? Thank you.
Hello,
I'm using 'ngx-quill' which is angular wrapper for quill JS. I need table import for my project but when I switch to quill 2.0.0-dev.3 version, I'm unable to bind data with [(ngModel)] in my view.
I tried following method :-
So in my view I have
<quill-editor [(ngModel)]="data" [modules]="quillConfig" placeholder="'Enter text here...'" style="min-height: 160px;" (onEditorCreated)="geteditor($event)"></quill-editor>
In .ts file I have:-
private editor: any;
ngOnInit(){
this.editor.setContents(this.editor.clipboard.convert("<p>Hello world</p>"));
}
geteditor(quillObj){
this.editor = quill;
}
still no luck! Can someone please help me out?
Thanks
I try to use quill-table and it worked when we insert a table. But when we load data from the database, the table tag was stripped.
Did anyone fix it?
@tungvn-vieted My most likely guess for that is that you're not including 'td' as an allowed format when initialising quill
@tungvn-vieted My most likely guess for that is that you're not including 'td' as an allowed format when initialising quill
Hmm, I registered like the quill-table documentation. I think the reason is quill is not supporting the table tags and strip it.
can you recreate it somewhere people can view? There's too many variables involved with very similar names to be able to debug it otherwise
@jhchen hey, is it even possible to implement multiple lines per cell or block level embeds (video) in cells? I tried to make TableCell as Container, but no luck. If it's possible, could you point me a correct way to move? thank you
We really need a patch to allow lists (and multi-line) inside of table cells. In additional, ability to resize columns. We are offering bounty of $2,500 for this if anyone can solve it!
@djcurfew which version of quill? quill-table for v1 can handle multiline, it's very very rough around the edges but I think it contains solutions for that and could also resolve column resizing (it'd be a huge pain though).
quill-better-table for v2 has resizing, the person working on it (@soccerloway ) didn't get around to multiline but might be a good person to contact
@tungvn-vieted Same problem here. When I get value for editor from DB as HTML string it can't render it as table. Did you manage to solve it ?
We really need a patch to allow lists (and multi-line) inside of table cells. In additional, ability to resize columns. We are offering bounty of $2,500 for this if anyone can solve it!
@djcurfew Did you get any response to this? I would be interested to team up on this and add to the bounty to get a solution for this as soon as possible.
@bhuisman @djcurfew I too would be pitching in with a small contribution of $100 for updating quill to 2.0 and having table support
@jhchen we would really appreciate your support here.
We really need a patch to allow lists (and multi-line) inside of table cells. In additional, ability to resize columns. We are offering bounty of $2,500 for this if anyone can solve it!
Perhaps I can be more specific on this topic. I would be interested to team up and add another $ 2,500 to the bounty to get this issue solved.
Can we just get a plain stupid way to render raw HTML markdown so we can do the tables and other things working together?
Most helpful comment
The long awaited table support is almost here! You can check out a demo with the latest 2.0 dev build here: https://codepen.io/quill/pen/QxypzX. The UI is not polished of course but the functionality is there. Having multiple editors on the page is meant to test the API and all changes from one should be perfectly produced in the other. I'll be filling out the 2.0 upgrade guide in the next week or two so you can try out tables in your own applications soon. The full 2.0 release will be further out but the dev build is meant to be well documented enough for the brave and eager to try.
In the meantime, help testing and reporting bugs in the demo would be greatly appreciated. Please comment with the bug report (must include your browser/os, steps for reproduction, expected and actual behavior -- there would be too much noise from back and forth otherwise).
The supported features tables features/limitations include:
I will not discuss including additional features here. Please open a separate feature request to request this.
As an administrative note, have marked existing comments as outdated and will also continue to delete all non-substantive comments from this thread to cut down the clutter and mass emails to everyone. Please use the Reaction feature to show support instead of commenting.