ckeditor5 icon indicating copy to clipboard operation
ckeditor5 copied to clipboard

Show helper lines when cells have border none

Open FilipTokarski opened this issue 4 months ago β€’ 14 comments

πŸ“ Provide a description of the improvement

Currently helper lines are displayed only on the whole table:

Image

This is a request to add them on cells as well.


If you'd like to see this improvement implemented, add a πŸ‘ reaction to this post.

FilipTokarski avatar Sep 01 '25 13:09 FilipTokarski

I pushed a PoC to https://github.com/ckeditor/ckeditor5/compare/ck/19039-show-helper-lines?expand=1

To me, it does the job (note, I used red dashed border as a helper line for this PoC):

Image

Reinmar avatar Sep 17 '25 21:09 Reinmar

@niegowski @pszczesniak Do you know why we went with outline instead of a border? And covered only the table? Border seems to work fine.

Also, why is there no layout tables in the all features test? Is it on purpose?

Reinmar avatar Sep 17 '25 21:09 Reinmar

@niegowski pointed out to me that those helper lines would then don't display if a table has a border but with a width set to 0px πŸ™ˆ

Image

However, AFAICS, that's the only scenario where the border-based solution falls short. It's actually good that the helper border is not displayed in this case, because that border would affect the layout.

One more scenario where I was worried we may break the layout is border-style: none; border-width: 5px. CKEditor would not produce such incoherent output, but it may be loaded or pasted into the editor. Fortunately, when border-style is set to none, the width does not have any effect:

Image

And that looks correct in the editor too:

Image

Proposal

So... I wonder if we should not create a combined solution:

  • use border (as in my PoC) for most cases – especially for the "set table border to none via table's UI" – it gives best results IMO
  • use outline as backup for a weirdly styled tables

Reinmar avatar Sep 18 '25 08:09 Reinmar

We were experimenting with outlines (https://github.com/ckeditor/ckeditor5/commit/7f2893641c7316366a9b87781d75d43c3f7d2264), but it is not possible to set outline only on selected sides, so it overlapped existing borders. We did not want to use borders as those take space in the content, and the editing view would differ from the data view, which affects pagination.

niegowski avatar Sep 18 '25 08:09 niegowski

Another proposal

Make the table cell position: relative, then add a pseudo-element that is positioned absolute and fills the entire cell. Set pointer-events: none on this element. With this approach, we can easily apply borders to each side of the cell without affecting the layout.

pszczesniak avatar Sep 18 '25 08:09 pszczesniak

I'm testing the direction proposed by @pszczesniak. It looks promising. Though, I'm unsure about some things.

⚠️ Note: I started with the table border first.

So, the positioned :before pseudoelement renders on top of the cells. Meaning that it covers the cells' borders. And similarly, cells without borders will affect cells with borders this way.

Unfortunately, I don't think it can be safely pushed back, to render below the table and its cells. It would also be susceptible to table and cells having a background color.

This is how it looks now (red is the help guide; I used 3px for text to see if things position well relative to each other):

πŸ‘‡ This is Chrome (Firefox looks good too):

Image

πŸ‘‡ And this is Safari πŸ™ˆ:

Image

How does it change with more realistic border? I tested a semi-transparent one so even when it renders above the cell's border it does not fully cover it.

πŸ‘‡ Chrome

Image

πŸ‘‡ Firefox

Image

πŸ‘‡ Safari

Image

Not bad, but unfortunately this border is visible over the styled cells. Pity, because it may be confusing. But just for the reference, this is how it looks on master:

Image

So, perhaps it's still an improvement?

Reinmar avatar Sep 19 '25 08:09 Reinmar

I added a border for cells too and unfortunately it surfaces a positioning problem I was afraid of:

πŸ‘‡ Chrome

Image

πŸ‘‡ Firefox

Image

πŸ‘‡ Safari

Image

It looks good only in Safari. In Chrome and Firefox the cells that have different border-width are positioned on non-zero offset from the table. I don't see a way to account for this.

This is the implementation, for reference: https://github.com/ckeditor/ckeditor5/commit/6efb0680ddddb1a29ebd9134da1ed2fa59ac60de

	& table[style*="border:none"]:before,
	& table[style*="border-style:none"]:before,
	& td[style*="border:none"]:before,
	& td[style*="border-style:none"]:before,
	& th[style*="border:none"]:before,
	& th[style*="border-style:none"]:before {
		content: '';
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		pointer-events: none;
		box-sizing: border-box;
		border: dashed 1px rgba(0, 0, 0, 0.1) !important;
	}

Reinmar avatar Sep 19 '25 09:09 Reinmar

So, for now:

  • The first approach: Use border of the table/cells in question:
    • Pros:
      • The borders will be positioned and combined between cells/table exactly where and how they'd normally be. No issues like https://github.com/ckeditor/ckeditor5/issues/19039#issuecomment-3311363633
      • Minimal impact on potential 3rd party / integrator's stylesheet. Lowest chance for a conflict.
    • Cons:
      • Might affect Pagination. I'd say it's the same impact as bookmarks have – both (guide borders and bookmarks) can be hidden in pagination. Or, we could even hide guide borders completely when Pagination is turned on.
      • Might slightly change the look of a table. I was curious to see impact on layouts such as in the Email editing demos, but I realized that layourt tables have their own outlines
  • The second approach: Use pseudoelement:
    • Pros:
      • No impact on the layout.
    • Cons:
      • Might conflict with someone's (even our's in the future) use of td/table:before.
      • Non-native to table layouts so may not position correctly.

I'd lean towards having this behaviour (showing guide borders) as an option. Probably, turned on by default. And having pagination turn it off or at least ignore when calculating pages.

Reinmar avatar Sep 19 '25 09:09 Reinmar

The whole idea of using a pseudo-element was that it does not affect the layout in the same way as outline, and it can be set on specific sides of the box, not on all sides like outline.

niegowski avatar Sep 19 '25 10:09 niegowski

I wanted to check one more time the approach with outline directly on table/td, but:

Image

So, I'd go with the borders.

Initially, with a config option to disable them.

In the future, we could have a user-facing option for toggling visual guides in the menu bar.

Reinmar avatar Sep 19 '25 10:09 Reinmar

The whole idea of using a pseudo-element was that it does not affect the layout in the same way as outline, and it can be set on specific sides of the box, not on all sides like outline.

How would you set it on specific sides? I can't imagine preventing issues like these ones: https://private-user-images.githubusercontent.com/156149/491488112-e6c865b0-3dfe-4b40-a9ff-84356b1408b8.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTgyNzk0MzAsIm5iZiI6MTc1ODI3OTEzMCwicGF0aCI6Ii8xNTYxNDkvNDkxNDg4MTEyLWU2Yzg2NWIwLTNkZmUtNGI0MC1hOWZmLTg0MzU2YjE0MDhiOC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwOTE5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDkxOVQxMDUyMTBaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT04NzVlNTRiZTYzMzlkNjFkZDNiNzY1NGEyODU3ZmQ0ZTY5ZGUwYWNlNGE2MWZhYWU1MDUxNzJiYTExMDVlOTg3JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.m8QUr5itKOovehnOKUzXYSNkHQvfjRjx7ilLTolYJYA

Reinmar avatar Sep 19 '25 10:09 Reinmar

Might be worth looking into when styling such helper UI elements: https://developer.mozilla.org/en-US/docs/Web/CSS/:where

Reinmar avatar Sep 19 '25 12:09 Reinmar

Might be worth looking into when styling such helper UI elements: https://developer.mozilla.org/en-US/docs/Web/CSS/:where

Turned out that CSS ecosystem is not yet ready to handle :where correctly. We've run into issues with PurgeCSS's lack of support for this selector which was breaking the output styles.

Reinmar avatar Sep 25 '25 14:09 Reinmar

Technical Summary

Based on the research conducted around CKEditor 5’s table border behaviour, the most reliable method for visualizing β€œhidden” borders (border: none) is to reapply a dashed border via CSS whenever the editor detects table elements whose inline styles explicitly remove borders.

When the initial data contains tables or cells styled with border:none or border-*-style:none, CKEditor keeps these styles in the editing view. Because these inline styles originate from the source data, they override normal CSS rules. This creates a challenge when attempting to visually indicate hidden borders inside the editor UI.

To achieve consistent overriding with minimal side effects, the implementation uses the :where() pseudo-class. This keeps all selectors at zero specificity, preventing conflicts with CKEditor’s own UI styles and ensuring that the editor’s widget system continues to function correctly.

Even with :where(), inline styles still carry the highest priority. Therefore, to display dashed preview borders in the editing view, the custom CSS must use !important. This makes it possible for the editor to visually mark elements that originally declared border:none or any side-specific border-*-style:none, without altering the underlying document data.

The CSS relies on attribute selectors (e.g., [style*="border:none"]) to detect both:

  • general border removal (border:none), and
  • side-specific removal (border-top-style:none, border-left-style:none, etc.).

This ensures that the visual preview in the editor is consistent with the actual border configuration defined in the source HTML.

To make the solution more flexible for different workflows, this functionality should be wrapped in a configuration option (e.g., table: { showHiddenBorders: true }). This allows integrators to disable the dashed-border visualization for use cases such as:

  • strict WYSIWYG scenarios where hidden borders should not be visually indicated,
  • custom themes or CSS frameworks that provide their own border-visibility logic,
  • minimalistic or distraction-free editing modes.

With this option, developers can tailor the editor to either provide visual guidance (dashed borders for hidden edges) or remain completely faithful to the original HTML styling.

The proposed CSS implementation uses dashed borders with the custom color variable --ck-table-border-none-helper-line-color, offering a clear editing aid without modifying the real HTML output.

Image

Conclusion

Using pseudo-elements to visualize hidden borders in CKEditor 5 tables:

❌ does not align with table layout rules ❌ cannot integrate with border collapsing ❌ is fragile and hard to maintain ❌ requires heavy CSS hacks

Using real CSS borders (overriding inline styles with !important) is:

βœ” layout-correct βœ” robust even with complex tables βœ” consistent with browser rendering βœ” maintainable

This is why the dashed-border override is the preferred solution.

PoC Implementation

Here is the commit from my research πŸ‘‰ https://github.com/ckeditor/ckeditor5/commit/7662f1329a40ff9809ccd9e6c91f7d331737bdfa

We need to check how it will work with layout tables.

Build systen

Also i've checked the PurgeCSS with top level :where and it works like it should. Styles are preserved during splitting to editor and content styles without any hacks.

pszczesniak avatar Dec 10 '25 07:12 pszczesniak