feat: add autoHeaderHeight option for multi-line column headers - #1282
Conversation
|
@jahanbakhsh18 feel free to click on the the "Resolve Comment" button when you've addressed any of the comments I left. also CCing @muendlein as well so that he's aware of the PR and can also provide feedback |
|
From my side I would also like to see an example where a column header is multiline HTML string or a DOM element. |
|
Thanks @muendlein for the suggestion. I created an additional example to check the feasibility of these scenarios with the current
...
const headerElement = document.createElement('p');
headerElement.style.margin= 0;
headerElement.innerHTML = `Customer <span style="color:red;">Information</span>`;
var columns = [
{ id: "sel", name: "#", field: "num", behavior: "select", cssClass: "cell-selection",
width: 30, cannotTriggerInsert: true, resizable: false, unselectable: true
},
{ id: "html-header", name: "Customer<br><strong style=\"color:red;\">Information</strong>",
field: "title", width: 100
},
{ id: "html-header-2", name: "Project<br><span style='font-size: 8px'>Status & Details</span>",
field: "title2", width: 100
},
{ id: "header-element", name: headerElement, field: "title3", width: 100 },
{ id: "description", name: "Very Long Header With Several Words", field: "title4", width: 150 }
];
var options = {
enableCellNavigation: true, enableColumnReorder: false, autoHeaderHeight: true, frozenColumn: 1
};
...
Note:The current implementation handles all of these cases without any additional changes. The header height is calculated from the rendered content, so the multi-line HTML and DOM element are included naturally in the measurement. |
|
@jahanbakhsh18 Thank you, this is looking good! |
|
Hey everyone, I asked Codex (ChatGPT 5.6) to review PR #1282, all PR comments, and the original issue #1272. This is only a second opinion for discussion, not a maintainer verdict. Context from issue #1272The original issue is specifically about preventing rendered content inside
The original issue prototype also identified a frozen-layout problem where the two header panes had different heights and the grid overflowed its container. Review findings1. High — header columns can still clip rendered contentThe PR changes Therefore, multi-line HTML or DOM content can still be clipped by its parent header column. Relevant rules: The auto-height styles should also override the parent column: .slick-header-column {
height: auto;
overflow: visible;
}The current measurement also removes height: calc(var(--slick-auto-header-height, auto) - 8px);
.slick-header-column {
height: auto;
height: calc(var(--slick-auto-header-height) - 8px);
overflow: visible;
}For Alpine: .slick-header-column {
height: auto;
height: calc(
var(--slick-auto-header-height) -
var(--alpine-auto-header-height-extra, v.$alpine-auto-header-height-extra)
);
overflow: visible;
}The first The current clipping test does not fully verify this because it checks the first header column, which is the 2. Medium — programmatic autosizing does not remeasure header height
This matters for Suggested change: reRenderColumns(reRender?: boolean) {
this.applyColumnHeaderWidths();
this.updateCanvasWidth(true);
if (this._options.autoHeaderHeight) {
this.recalculateHeaderHeight();
}
this.trigger(this.onAutosizeColumns, { columns: this.columns });
if (reRender) {
this.invalidateAllRows();
this.render();
}
}The existing manual column resize path already recalculates at resize end, which is preferable to recalculating on every mouse-move. 3. Medium — container resizing needs to trigger recalculationThe current container resize handler only calls: this.resizeCanvas.bind(this)If the grid width changes responsively, header wrapping can change while the stored header height remains stale. A minimal change would be: this._bindingEventService.bind(this._container, 'resize', () => {
if (this._options.autoHeaderHeight) {
this.recalculateHeaderHeight();
} else {
this.resizeCanvas();
}
});If the application relies on ordinary CSS/container resizing, a 4. Medium — frozen rows need explicit regression coverageThe original issue identified problems with both frozen columns and frozen rows:
The PR currently tests frozen columns, but not a frozen-row configuration. At minimum, add a test using: grid.setOptions({
autoHeaderHeight: true,
frozenColumn: 2,
frozenRow: 5
});The test should verify: cy.get('.slick-header-left .slick-header-columns').then(($left) => {
cy.get('.slick-header-right .slick-header-columns').should(($right) => {
expect(Math.abs(
$left[0].offsetHeight - $right[0].offsetHeight
)).to.be.lessThan(2);
});
});
cy.get('#myGrid').should(($grid) => {
expect($grid[0].scrollHeight)
.to.be.lte($grid[0].clientHeight + 1);
});If this test fails, the fix belongs in Because header height and available width can affect scrollbar presence, the recalculation should also use an only-if-changed guard or a bounded second pass. 5. Medium — the requested HTML/DOM scenarios are not committed as testsThe original issue explicitly mentions HTML strings and DOM elements. The PR discussion includes an additional example in a comment, but the committed example and Cypress spec do not currently test those cases. Suggested test setup: const headerElement = document.createElement('p');
headerElement.style.margin = '0';
headerElement.innerHTML = 'Customer <strong>Information</strong>';
const columns = [
{
id: 'html',
name: 'Customer<br><strong>Information</strong>',
field: 'title',
width: 100
},
{
id: 'dom',
name: headerElement,
field: 'title',
width: 100
}
];The Cypress test should inspect every rendered header, not only the first column: cy.get('.slick-header-column').each(($header) => {
const header = $header[0] as HTMLElement;
expect(header.scrollHeight).to.be.lte(header.clientHeight);
});6. Minor — trailing whitespaceThere is trailing whitespace at: SlickGrid/src/styles/slick.grid.scss Line 289 in e654893 Verification
Overall recommendationThe PR has the right general direction and correctly keeps the feature opt-in. However, before merging, I recommend fixing the parent-column overflow and CSS fallback, adding recalculation after programmatic and responsive width changes, and adding regression coverage for HTML/DOM titles and frozen rows. The current tests demonstrate the fixed example scenario, but they do not yet fully prove the requirements described in issue #1272. |
|
@ghiscoding @muendlein Thank you both for the detailed feedback, and apologies for the delayed response... I’ve spent some time going through the interactions between Regarding
This should make the examples and regression tests much easier to understand and should also directly cover the scenario you mentioned, @muendlein. I’ll continue with the remaining review points once these interactions are settled. Thanks again for the feedback and for your patience. |
|
@6pac, @ghiscoding, @muendlein please accept my apologies for the delay on this PR. While testing Review 2: “Programmatic autosizing does not remeasure header height”, I noticed that simply adding I’m working through the remaining reviews now and will do my best to finalize and cover all six reviews ASAP. Thank you for your patience! |
|
oops my latest PRs caused a single line conflict, shouldn't be too hard to fix though which seems to be to keep both lines. |
- Add autoHeaderHeight boolean option (default: false) - Support multi-line header text - Equalize left/right header heights for frozen columns - Auto-recalculate on column resize - Add example and Cypress tests
- Remove center alignment (use theme default) - Add SASS variables for Alpine theme - Simplify _setAutoHeaderHeightStyles by removing constants - Call recalculateHeaderHeight on init and column update
Co-authored-by: Ghislain B. <gbeaulac@gmail.com>
- prevent header content clipping in Classic and Alpine themes - recalculate header height after programmatic column autosizing - add autosize mode example covering all supported algorithms - expand Cypress coverage for header content, frozen panes, and autosizing - prevent recursive rendering with LegacyForceFit
e654893 to
3852589
Compare
|
Hi everyone, What was updated
I also added a second example specifically for demonstrating the interaction between Auto Header Height and the different column autosizing modes. Demo: Auto Header Height and Autosize Modesexample-auto-header-height-autosize.mp4Thanks again for the reviews and guidance. I believe the current implementation and test coverage now provide a good regression suite for the original issue. |
|
@jahanbakhsh18 I've asked Codex for another review and it still identified some small change requests, could you please look into this? If you need help, I can always ask Codex to fix it, let me know if you need help or not. It would be great to have this released this week. Thanks Here's the Codex review with code suggestions separated in 2 comments: Thanks for the work on this — the feature direction looks good. I think we need one implementation update and stronger regression coverage before merging. Programmatic autosizing leaves auto header height stale
This matters for the Suggested change: reRenderColumns(reRender?: boolean) {
this.applyColumnHeaderWidths();
this.updateCanvasWidth(true);
if (this._options.autoHeaderHeight) {
this.recalculateHeaderHeight();
}
this.trigger(this.onAutosizeColumns, { columns: this.columns });
if (reRender) {
this.invalidateAllRows();
this.render();
}
} |
|
Thanks @ghiscoding! Could you please check the latest commit of the PR once more? I believe some of these comments may be based on an earlier version. The latest version already includes:
I’ll be happy to add anything that is still missing after reviewing the latest version 🙂 |
|
oops you're right, my bad, I did a git checkout of your branch again to do the review but forgot to git pull recent changes, dohhhh 🤦🏻♂️🤣 doing another review now |
|
ok it replied with: Yes — after updating to The author addressed the earlier blockers:
I found no remaining merge-blocking issue and have no required code suggestions. ... so it looks good and ready to merge, I'll do that later today and maybe go with a new release too |
|
If you guys are happy with it, go ahead |
|
Thanks again for your contribution, I'll push a new release soon :) |

Add
autoHeaderHeightoption for multi-line column headersThis PR adds a new
autoHeaderHeightgrid option that allows column headers to auto-size based on their content.Closes #1272
Features
autoHeaderHeightis enabled or disabled throughsetOptionsThe grid core handles measuring and synchronizing the required header height. The calculated dimensions are passed to the themes through CSS custom properties, allowing to retain their respective header layout behavior.
Demo
A short demo video and screenshots are attached below.
example-auto-header-height.mp4