Better Table engine? Or to be considered: A real spreadsheet engine as table alternative ... after all these years?
Describe the feature you'd like
I use tables in Bookstack A LOT. There are unfortunately quite a few limitations:
- no scrollbars = no option to go beyond page width = limited number of columns, due to limited width
- with no scrollbars come no optionally fixed header lines
- no interactive method to adjust width/height of multiple selected columns/lines at once in order to be identical in size
- no option to drag and re-sort entire columns or lines
- no sorting options
- no real option to paste formatted table contents sourced e.g. from Excel or Google Sheets
- and: no calculations (not expected ... but still would come very handy)
@ssddanbrown Can’t you switch the table engine or add an alternative one? Why not implement a JavaScript Spreadsheet Engine like e.g. JSpreadsheet CE, Handsontable, DHTMLX Grid or Webix Grid ... instead or as alternative? While being commercial libraries it looks to me as if they all are also available in free community editions for integration in non-commercial open source application like Bookstack.
Describe the benefits this would bring to existing BookStack users
My above described limitations are described in countless other issues: #1387, #4522, #5743, #1652 (interesting ... created by myself 6 years ago), #1574, #2126, #4716, #5717, #4944, #1367, #315, #1518, #1492, #3475 and the list goes on.
IMO many users, including me, are eagerly and yearningly awaiting a fundamental improvement on the tables front since years and the applause and sighs of relieve would be long and loud.
Can the goal of this request already be achieved via other means?
No.
Have you searched for an existing open/closed issue?
- [x] I have searched for existing issues and none cover my fundamental request
How long have you been using BookStack?
Over 5 years
Additional context
No response
Hi @Wookbert,
Ultimately it comes down to scope of support. Adding anything more complex broadens the scope to maintain that complexity. This would be especially true of a spreadsheet engine as that would take on a wide new element which would bring its own requests, desires and support needs. Ultimately I'm not confident it's worthwhile for the project to also become a spreadsheet engine, that's probably better done via a dedicated application (and potentially embedded into BookStack content if really needed).
Why not implement a JavaScript Spreadsheet Engine like e.g. JSpreadsheet CE, Handsontable, DHTMLX Grid or Webix Grid ... instead or as alternative? While being commercial libraries it looks to me as if they all are also available in free community editions for integration in non-commercial open source application like Bookstack.
From a quick look all those are non-starters based on their licensing alone, either not being compatible with our permissive license or being open core which I wouldn't be keen to rely on. Either way, It's not just a drop-in usage. As long as it's officially and properly integrated, we'll end up assuming responsibility of these elements so support will end up on me/us, and there's still a lot of consideration in regard to working-well/integrating with the required features of BookStack. Even then, we'd have to consider the potential impact of taking on the efforts of maintaining the functionality ourselves in the event it stops being maintained, or there's a fundamental change upstream, where forward compatibility would be needed. This is something we're currently experiencing with the main WYSIWYG editor, which has required a lot of effort, in addition to other parts such as codemirror languages. That would be a massive burden on the project.
Ultimately, I do want to improve the experience of tables, and maybe the move to our own WYSIWYG editor will help with options there, but a lot of the direct solutions to issues raised have trade-offs or issues of their own relative to other fundamentals of the platform, and therefore are not an overall win. Some I feel are best left to non-official customizations so trade-offs have to be considered. Maybe we could better formalise a range of customizations on our hacks site?
Tables though are a fundamentally complex and awkward structure, and often when looking deeper into the more complex issues around them, I come away thinking that alternative layouts/structures would be better suited in general.
Some I feel are best left to non-official customizations so trade-offs have to be considered. Maybe we could better formalise a range of customizations on our hacks site?
We can't meet everyone's needs, but I think a plugin-like format can give everyone the opportunity to fulfill their own wishes.
@ssddanbrown As always: Thanks for your swift reply and honest words!
I'm not a programmer, I’m just a passionate user – and unfortunately those stupid tables are essential to nearly every BookStack page I create. Whenever I begin a new documentation and it comes to creating a table (e.g. to collect data or make a hardware, software, component comparison, ...) I’m standing at the crossroads between having everything neatly in one place in BookStack, but running into getting bloody fingers with those TinyMCE tables, or using Google Sheets and adding a text link (which is a bit annoying, because it’s not in plain sight and requires some additional organizing on the Google Drive).
In most cases I start with the TinyMCE tables, but as it is a work in progress and I’m for instance not knowing how many columns I end up with, creating an appealing result is really a time-consuming challenge, where at certain point I ask myself „Heck, why didn’t I went down the Google Sheets road this time“. I seldomly need its mathematical features, but the way to edit and organize the table is much, much more convenient.
So, yes I stand by my request ... a better table editor or table something is needed. I dunno... Either by building your own engine (perhaps you could »borrow« some code from the mentioned commercial OS projects) or perhaps by elegantly implementing a Google Sheets viewer right into BookStack pages, something which seamlessly blends in. I totally understand: It’s quite a challenge ...
On those JavaScript table engines again: I’ve mentioned just a few which look cool to me (SheetsJS might also be worth a look). Perhaps there’s something out there which fits. Perhaps it’s not a spreadsheet engine, but a dumb, yet more powerful table engine.
A few more candidates (quick collection, not reviewed in depth by me):
- Grid.js
- https://github.com/bennyboer/table-engine | Demo ... no updates since 2022
- Tabulator
- DataTables
- Tanstack Tables ... no clue what this is
- MUI X Data Grid
- Bootstrap Table
- vue-good-table
Every problem actually has many solutions. In my opinion, before online editors offer better table support, you can try changing your workflow. For example, use an offline editor to process the entire document and then copy it into the online editor. Although this method may not necessarily work for you, it is perhaps one of many solutions. You should be able to find other solutions that suit you.
@zhang-nianqiang
We can't meet everyone's needs
We? I’m not quite sure what your role in the BookStack community is – at least I can’t find your profile in the Top 100 list of development contributors.
you can try changing your workflow. … You should be able to find other solutions that suit you.
Your comments sound overly ambitious, however are no helpful at all. My feature request is a respectful reminder and constructive criticism from me as whole-hearted BookStack user and supporter, that tables are a fundamental element of Wiki-style editing/documentation as in BookStack, yet the current TinyMCE table engine lacks features and a certain degree of convenience, and come with major limitations (such as the page width limit without scrollbars), which users are knowingly dealing (and struggling) with since years (see the not even complete list if issue numbers in my OP above).
I – like probably many here, who are constantly working/juggling with tables in BookStack – am craving for something which gives me less of a headache and a bit more fun, and saves me time, rather than taking it.
@ssddanbrown Thought about it again... A useful, yet not overly complex (sorry if I’m naive) improvement of the situation might be the already mentioned Inline Viewer for Google Sheets. So instead of a text link to a Google Sheets document, a (height-adjustable) area with scrollbars, which shows the Sheet title and the cells area minus the toolbar(s). Fully viewable and cells selectable for copying, but no editing. For editing a pen icon next to the Sheets Document title takes you to the Google website and opens the Sheets. No idea whether this can be done.
What about embeddability of something like PySpread? It has a pretty solid REST API as I recall from my limited experiments a while ago.
This might get you partially there in Customizations:
// --- Logic for Table Expander ---
const expandIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M3 3l7 7M21 21l-7-7"/></svg>`;
const closeIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>`;
const tables = document.querySelectorAll('.page-content table');
tables.forEach(table => {
const outerWrapper = document.createElement('div');
outerWrapper.className = 'table-outer-container';
const innerWrapper = document.createElement('div');
innerWrapper.className = 'table-inner-scroll';
table.parentNode.insertBefore(outerWrapper, table);
outerWrapper.appendChild(innerWrapper);
innerWrapper.appendChild(table);
const isOverflowing = table.offsetWidth > innerWrapper.offsetWidth;
if (isOverflowing) {
const button = document.createElement('button');
button.className = 'table-expand-button';
button.innerHTML = expandIcon;
button.setAttribute('aria-label', 'Expand Table');
outerWrapper.appendChild(button);
button.addEventListener('click', (e) => {
e.stopPropagation();
const isExpanded = outerWrapper.classList.toggle('expanded');
if (isExpanded) {
const scrollY = window.scrollY;
document.body.style.setProperty('--body-scroll-y', `-${scrollY}px`);
document.body.classList.add('body-no-scroll');
button.innerHTML = closeIcon;
button.setAttribute('aria-label', 'Close Table');
} else {
const scrollY = document.body.style.getPropertyValue('--body-scroll-y');
document.body.classList.remove('body-no-scroll');
document.body.style.removeProperty('--body-scroll-y');
window.scrollTo(0, parseInt(scrollY || '0') * -1);
button.innerHTML = expandIcon;
button.setAttribute('aria-label', 'Expand Table');
}
});
outerWrapper.addEventListener('click', (e) => {
if (outerWrapper.classList.contains('expanded') && e.target === outerWrapper) {
button.click();
}
});
} else {
outerWrapper.parentNode.insertBefore(table, outerWrapper);
outerWrapper.remove();
}
});
@ssddanbrown I'm much less emotionally attached to the topic, but I can say that the cumbersome handling of tables is the one aspect that has prevented me from adopting BookStack in my professional environment. I do have started to play with custom styles though, something I've tried to avoid at any cost, because the rest of BookStack is just too good to be ignored.
I fully understand that you don't want to turn the tables support into a swiss army knife of spreadsheet features, and also that including external libraries - even if they are compatible from a license and technical point of view - is something that comes with a long-term committment, maintenance cost and potentially many more additional feature requests once the flood gate is open. In your shoes, I also would not consider this at all. And, frankly, I'm also glad you don't, because what I personally like about BookStack is that it stayed and stays true to its vision without diluting the core features over the years - something that I've sadly seen in too many good projects in the past.
That said, I think there is some low-hanging fruits, or at least things that are possible without disruption and new external dependencies. For example, the few things that I finally committed to as custom styles, are:
1. Sticky Headers
It is very annoying to have large tables where you need to scroll back up to remind yourselves of what the column contents are - especially in typically of my use cases where the same information is captured in columns, but with different semantics (think: source vs. target).
table thead {
position: sticky;
top: -1px;
}
I use -1px to accommodate for the default transparent borders, and avoid the tiny line of 1 pixel of content that is visible when scrolling.
I think this could be turned on by default and nobody would complain.
2. Auto-Layout
Especially when you only have few columns of vastly different content, like one column with text and another one that only contains an abbreviation or a checkmark, it is very annoying that columns take a fixed amount of space. I override the layout to:
.page-content table {
table-layout: auto !important;
}
table colgroup col {
width: auto !important;
}
Not pretty due to the !important enforcement, but it gets the job done.
I understand that this may be a matter of personal taste or the respective use case. Instead of making it a potentially undesired breaking change for all users, it could be a global option, or even a per-table setting.
Note that I'm not sure if the "resize to contents" option for tables in the editor is supposed to somehow influence this, for me it didn't.
3. Wide tables
This is the most difficult one for me, and probably also for you, because it potentially affects the very fundamentals of your screen layout principles. Instead of scrolling, which I personally think doesn't anything to an improved UX (quite the opposite actually), I would like to see an option to let tables break out of the layout horizontally, and make use of the available screen estate if available (and necessary).
Since this is just too much of a hack for my taste to be put into custom styles and scripts, I have approached this in a different way. With surgical precision I turn off the max-width restrictions of the content. To avoid JavaScript, I use a CSS-only solution that looks for a certain tag on the page (tag as in page tag, not HTML tag).
I am not fully happy with that because it taints the page tags with a helper that has no business or domain semantics, and because the side effect of that also is that the content width becomes quite large on wide monitors in fullscreen mode, which degrades the reading experience of text. The latter is not a real problem for me, as in my use cases wide tables are mostly standing alone on separate pages, not combined with "normal" content.
#content:has(div.tag-value):has(a[href*='width%3Dfull']) {
#main-content {
max-width: 100%;
}
#main-content .page-content {
max-width: 100%;
}
}
The tag needs to be "width" with a value of "full" in this example.
I don't see how this could be easily included in your concept without quite some work. The most pragamtic or simplest solution in my opinion would be to offer a "full width" button to readers on a page that basically does exactly the above, so you could at least toggle the behavior on demand if you want.
Conclusion
I agree that the goal should often be to find a different structure for your content, instead of using massive tables. However, these use cases are reality and often cannot be avoided. Whatever you use BookStack for, concepts, protokolls, task descriptions, technical documentation, there simply often is the need to keep track of something as a list of things which is not available somewhere else (in another system). If you want to keep all your content cohesively in one place and not resort to working with yet another system just for tabular data, using tables in BookStack is the way to go.
Again, for me personally this is the one thing that stood in the way, and has for quite some years now. I hope for at least some improvements that don't require hacks, maybe on the basis of the new editor(?).