Patch #43641
open
Make the issues list header sticky on vertical scroll
Added by Takashi Kato 3 months ago.
Updated about 18 hours ago.
Description
This patch implements a sticky header for the issue list when scrolling.
While currently limited to issues, this approach can be applied to other list views as well.

Limitations¶
The header will not be fixed under the following conditions: When a horizontal scrollbar is present, the sticky header becomes detached from the table body.
Since it is impossible to synchronize the widths of the header and the table in this state, the feature is disabled for:
- Narrow windows where a horizontal scrollbar is displayed.
- Mobile mode.
State Transition Table¶
| |
state |
state |
event |
event |
event |
| |
Horizontal scrollbar |
table and window |
start |
change state of a horizontal scrollbar |
change state of overlapping table and window |
| 1 |
none |
not overlapping |
header: normal |
→2 |
set sticky →3 |
| 2 |
displayed |
not overlapping |
header: normal |
→1 |
→4 |
| 3 |
none |
overlapping |
header: sticky |
set header normal →4 |
set header normal →1 |
| 4 |
displayed |
overlapping |
header: normal |
set header sticky→3 |
→2 |
Files
The screencast is here.

This feature significantly improves the usability of tables in Redmine. Thank you for providing the patch.
After testing it locally, I encountered an issue when the % Done column is displayed. The problem occurs because the progress bar inside the % Done column is also recognized as column content. It seems that modifying the code as shown below resolves the issue.
diff --git a/app/javascript/controllers/sticky_table_header_controller.js b/app/javascript/controllers/sticky_table_header_controller.js
index ee804ae36..2f31c5bb1 100644
--- a/app/javascript/controllers/sticky_table_header_controller.js
+++ b/app/javascript/controllers/sticky_table_header_controller.js
@@ -20,7 +20,7 @@ export default class extends Controller {
prepare() {
if (!!this.prepared === false) {
- this.bodyColumns = this.bodyTarget.querySelectorAll("tr:first-child td")
+ this.bodyColumns = this.bodyTarget.querySelectorAll(":scope > tr:first-child > td")
this.stickyHeader = this.headTarget.cloneNode(true)
this.stickyHeader.removeAttribute(`data-${this.identifier}-target`)
In addition, when "Group results by" is enabled, I noticed that the width of the sticky header is affected by the group rows.

Mizuki ISHIKAWA wrote in #note-2:
In addition, when "Group results by" is enabled, I noticed that the width of the sticky header is affected by the group rows.
I had previously pointed out the issue mentioned above, but I just checked again and was able to reproduce it. It might have been an issue specific to my environment.
Separately, I have written a patch to fix an issue where, in responsive mode with a small number of columns (so no horizontal scrolling occurs), the sticky header ends up hidden behind #project-jump and becomes invisible.
- The issue mentioned in #note-2 occurs when the first
tr element has a colspan attribute.
- I have fixed the above issue and attached a new patch that includes the fix from #note-3.
- This patch determines which row is referenced by the sticky header on the server side, making the Stimulus controller slightly simpler.
Also available in: Atom
PDF