[EuiDataGrid] Support rendering the header optionally#9281
[EuiDataGrid] Support rendering the header optionally#9281mgadewoll merged 7 commits intoelastic:mainfrom
Conversation
33a1a55 to
92feee7
Compare
- the getRow method may return undefined
92feee7 to
be49e96
Compare
packages/eui/src/components/datagrid/body/data_grid_body.styles.ts
Outdated
Show resolved
Hide resolved
packages/eui/src/components/datagrid/body/data_grid_body_virtualized.tsx
Outdated
Show resolved
Hide resolved
weronikaolejniczak
left a comment
There was a problem hiding this comment.
The showHeader code changes look good 👍🏻 I shared some doubts in separate comments.
Testing notes
Header and toolbar visibility (tested here)
Toolbar and header display as expected. gridStyle.border is default here, so "all" for all 4 cases.
✅ default headerVisiblity={true} & default toolbarVisibility
| HCM off | HCM on | |
|---|---|---|
| Light mode | ![]() |
![]() |
| Dark mode | ![]() |
![]() |
✅ default headerVisiblity={true} & toolbarVisibility={false}
| HCM off | HCM on | |
|---|---|---|
| Light mode | ![]() |
![]() |
| Dark mode | ![]() |
![]() |
✅ headerVisiblity={false} & toolbarVisibility={false}
| HCM off | HCM on | |
|---|---|---|
| Light mode | ![]() |
![]() |
| Dark mode | ![]() |
![]() |
✅ headerVisiblity={false} & default toolbarVisibility
| HCM off | HCM on | |
|---|---|---|
| Light mode | ![]() |
![]() |
| Dark mode | ![]() |
![]() |
Different gridStyle, focusing on border (docs, tested here)
There are no missing or doubled borders. Tested in light mode with HCM off.
✅ horizontal
default headerVisibility={true} |
headerVisibility={false} |
|
|---|---|---|
default toolbarVisibility |
![]() |
![]() |
toolbarVisibility={false} |
![]() |
![]() |
✅ none
default headerVisibility={true} |
headerVisibility={false} |
|
|---|---|---|
default toolbarVisibility |
![]() |
![]() |
toolbarVisibility={false} |
![]() |
![]() |
Screen reader output (tested here)
Because we enrich each cell with screen-reader-only text, not rendering the header doesn't have detrimental effect to a11y. Actually, it yields better screen reader announcements because they are not polluted by the column cell announcements (e.g. "Press the Enter key to view this column's actions" when the Enter key is already mapping to "expanding the cell"). In the JAWS case, the column header is repeated if the header is present.
💡 It could be a nice opportunity to think about:
Is there an easy way we could include this change?
✅ (MacOS) VoiceOver + MacOS
| With header | Without header |
|---|---|
Kapture.2025-12-31.at.12.11.57.mp4 |
Kapture.2025-12-31.at.12.09.42.mp4 |
💭 The only difference seems to be that if the header is present, the number of columns and rows is read out. If it's not present, that data is omitted. And we do pass aria-rowcount directly. Not sure why that is.
✅ (Win) NVDA + Firefox
| With header | Without header |
|---|---|
Kapture.2025-12-31.at.12.26.23.mp4 |
Kapture.2025-12-31.at.12.23.20.mp4 |
💭 (out of scope) The NVDA + data grid experience is very confusing due to browse mode. Only once I browse to a specific cell with arrow down and tab, can I then navigate with the arrow keys. Do you know why that is and if it's something we can improve?
✅ (Win) JAWS + Chrome
| 🔈 With header | 🔈 Without header |
|---|---|
Kapture.2025-12-31.at.12.35.00.mp4 |
Kapture.2025-12-31.at.12.32.23.mp4 |
Potential prod regression
Based on code changes, I tested these potential regression spots:
✅ there are no missing or double borders
✅ on initial render, the data grid displays correctly both with and without the header
✅ when dynamically toggling headerVisibility, the scroll offset is applied correctly and there is no layout shift or jumpiness
✅ there are no renderCustomGridBody usages that access headerRow property without checking for null (no such cases in Kibana)
I couldn't verify this point because I cannot reproduce the issue, even with simulated CPU throttling:
❓ verified the isMounting logic prevents flickering and doesn't leave cells in an invisible state
Personally, if it's not caused or significantly worsened by the changes on the PR, I'd move it to a separate PR with clear steps to reproduce.
- reverts previous changes to hide rows on initial render via css
💚 Build SucceededHistory
cc @mgadewoll |
💚 Build Succeeded
History
cc @mgadewoll |
weronikaolejniczak
left a comment
There was a problem hiding this comment.
🟢 I tested the new solution to the row flickering and smoke-tested the headerVisibility and toolbarVisibility. The code looks good and the component works as expected 👍🏻 Thank you for your attention to detail and for the patience with the review 🙏🏻
|
@weronikaolejniczak Thank you for the thorough review! 🙏 |
## Dependency updates - `@elastic/eui`: `v111.1.0` ⏩ `v112.0.0` - `@elastic/eslint-plugin-eui`: `v2.6.0` ⏩ `v2.7.0` --- ## Package updates ### `@elastic/eui` [v112.0.0](https://github.com/elastic/eui/releases/tag/v112.0.0) - Added `productDiscover` icon ([#9311](elastic/eui#9311)) - Updated `chartGauge` icon glyph ([#9311](elastic/eui#9311)) - Updated icon glyphs `endpoint` `eraser` `errorFill` `error` `eyeSlash` `faceHappy` `faceNeutral` `faceSad` `folder` `fullScreenExit` `fullScreen` `gradient` `grid` `heart` `home` `if` `image` `infinity` `inputOutput` `key` `keyboard` `lineBreakSlash` `lineBreak` `lineDash` `lineDot` `lineSolid` `logOut` `magnifyMinus` `magnifyPlus` `magnify` `mail` `map` `mapping` `menuLeft` `menuRight` `menu` `merge` `minusCircle` `minusSquare` `minus` `money` `moon` `move` `nested` `number` `package` `paintBucket` `palette` `paperClip` `partial` `pattern` `pause` `pencil` `percent` `pinFill` `pin` `pivot` `plusCircle` `plusSquare` `plus` `popper` `presentation` `processor` `productStreamsWired` `queryField` `queryOperand` `querySelector` `queryValue` `query` `question` `quote` `radar` `readOnly` `redo` `reporter` `return` `rocket` `scissors` `send` `shard` `share` `snowflake` `sortAscending` `sortDescending` `starFill` `star` `stop` `sun` `tableInfo` `tableTime` `textAlignCenter` `textAlignLeft` `textAlignRight` `textBold` `textHeading` `textItalic` `textStrike` `textUnderline` `thermometer` `thumbDown` `thumbUp` `timeline` `transitionLeftIn` `transitionLeftOut` `transitionTopIn` `transitionTopOut` `undo` `vectorSquare` `vectorTriangle` `videoPlayer` `warningFill` `waypoint` `wifiSlash` `wifi` ([#9303](elastic/eui#9303)) ([#9303](elastic/eui#9303)) - Added icons - `archive` `unarchive` `axisX` `axisYLeft` `axisYRight` `bulb` `cloud` `hourglass` `megaphone` `workflow` ([#9303](elastic/eui#9303)) - Added `headerVisibility` prop on `EuiDataGrid` to support rendering the datagrid header element optionally ([#9281](elastic/eui#9281)) - Updated 244 icon definitions to a more consistent naming convention. All 100 renamed icons include a backward-compatible alias in the icon map to support legacy references. ([#9279](elastic/eui#9279)) - Added icons `briefcase`, `productCloudInfra`, `productDashboard`, `productML` ([#9301](elastic/eui#9301)) - Updated glyphs `bullseye`, `bolt` ([#9301](elastic/eui#9301)) - Added `dismissButtonProps` prop to `EuiCallOut` ([#9285](elastic/eui#9285)) **Bug fixes** - Fixed `EuiFlyout` to properly forward refs when `session` prop is used. ([#9318](elastic/eui#9318)) - Fixed `EuiDataGrid` cells scrolling into view while trying to select text ([#9276](elastic/eui#9276)) **Breaking changes** - Removed `euiPaletteForLightBackground` and `euiPaletteForDarkBackground` deprecated palette functions. Use `euiTheme.colors.vis.euiColorVisText{NUMBER}` tokens instead. ([#9296](elastic/eui#9296)) **Accessibility** - Improved the accessibility of `EuiDataGrid`s column selector drag handle buttons by ensuring distinctive labels ([#9282](elastic/eui#9282)) ### `@elastic/eslint-plugin-eui` v2.7.0 - Added `no-static-z-index` rule ([#9236](elastic/eui#9236))
## Dependency updates - `@elastic/eui`: `v111.1.0` ⏩ `v112.0.0` - `@elastic/eslint-plugin-eui`: `v2.6.0` ⏩ `v2.7.0` --- ## Package updates ### `@elastic/eui` [v112.0.0](https://github.com/elastic/eui/releases/tag/v112.0.0) - Added `productDiscover` icon ([elastic#9311](elastic/eui#9311)) - Updated `chartGauge` icon glyph ([elastic#9311](elastic/eui#9311)) - Updated icon glyphs `endpoint` `eraser` `errorFill` `error` `eyeSlash` `faceHappy` `faceNeutral` `faceSad` `folder` `fullScreenExit` `fullScreen` `gradient` `grid` `heart` `home` `if` `image` `infinity` `inputOutput` `key` `keyboard` `lineBreakSlash` `lineBreak` `lineDash` `lineDot` `lineSolid` `logOut` `magnifyMinus` `magnifyPlus` `magnify` `mail` `map` `mapping` `menuLeft` `menuRight` `menu` `merge` `minusCircle` `minusSquare` `minus` `money` `moon` `move` `nested` `number` `package` `paintBucket` `palette` `paperClip` `partial` `pattern` `pause` `pencil` `percent` `pinFill` `pin` `pivot` `plusCircle` `plusSquare` `plus` `popper` `presentation` `processor` `productStreamsWired` `queryField` `queryOperand` `querySelector` `queryValue` `query` `question` `quote` `radar` `readOnly` `redo` `reporter` `return` `rocket` `scissors` `send` `shard` `share` `snowflake` `sortAscending` `sortDescending` `starFill` `star` `stop` `sun` `tableInfo` `tableTime` `textAlignCenter` `textAlignLeft` `textAlignRight` `textBold` `textHeading` `textItalic` `textStrike` `textUnderline` `thermometer` `thumbDown` `thumbUp` `timeline` `transitionLeftIn` `transitionLeftOut` `transitionTopIn` `transitionTopOut` `undo` `vectorSquare` `vectorTriangle` `videoPlayer` `warningFill` `waypoint` `wifiSlash` `wifi` ([elastic#9303](elastic/eui#9303)) ([elastic#9303](elastic/eui#9303)) - Added icons - `archive` `unarchive` `axisX` `axisYLeft` `axisYRight` `bulb` `cloud` `hourglass` `megaphone` `workflow` ([elastic#9303](elastic/eui#9303)) - Added `headerVisibility` prop on `EuiDataGrid` to support rendering the datagrid header element optionally ([elastic#9281](elastic/eui#9281)) - Updated 244 icon definitions to a more consistent naming convention. All 100 renamed icons include a backward-compatible alias in the icon map to support legacy references. ([elastic#9279](elastic/eui#9279)) - Added icons `briefcase`, `productCloudInfra`, `productDashboard`, `productML` ([elastic#9301](elastic/eui#9301)) - Updated glyphs `bullseye`, `bolt` ([elastic#9301](elastic/eui#9301)) - Added `dismissButtonProps` prop to `EuiCallOut` ([elastic#9285](elastic/eui#9285)) **Bug fixes** - Fixed `EuiFlyout` to properly forward refs when `session` prop is used. ([elastic#9318](elastic/eui#9318)) - Fixed `EuiDataGrid` cells scrolling into view while trying to select text ([elastic#9276](elastic/eui#9276)) **Breaking changes** - Removed `euiPaletteForLightBackground` and `euiPaletteForDarkBackground` deprecated palette functions. Use `euiTheme.colors.vis.euiColorVisText{NUMBER}` tokens instead. ([elastic#9296](elastic/eui#9296)) **Accessibility** - Improved the accessibility of `EuiDataGrid`s column selector drag handle buttons by ensuring distinctive labels ([elastic#9282](elastic/eui#9282)) ### `@elastic/eslint-plugin-eui` v2.7.0 - Added `no-static-z-index` rule ([elastic#9236](elastic/eui#9236))
























Summary
Closes https://github.com/elastic/eui-private/issues/475
Closes #9000
This PR updates
EuiDataGridto add support for a conditionally rendered header element via a new prop:headerVisibility. The naming is chosen to be in line with the existingtoolbarVisibilityfor the external facing API.headerVisibilitybooleantrueAccessibility
Generally not rendering the header element is not adviced for semantic tables, as its required for providing contextual information to screen readers.
The current implementation of
EuiDataGridadds the contextual information as screen reader only text to each cell which ensures that accessibility is kept as is.Screen.Recording.2025-12-18.at.09.09.155.mov
Why are we making this change?
✨ Feature request: Serving a Kibana feature request.
Screenshots #
Screen.Recording.2025-12-18.at.15.07.11.mov
Usage with
headerVisibility=false+toolbarVisibility=falseImpact to users
🟢 No updates required on consumer side. This is a new, opt-in feature.
QA
headerVisibilityonEuiDataGridand verify it works as expected (ensure to test in different combinations: withtoolbarvisibilitywith differentborderstyles etcGeneral checklist
@defaultif default values are missing) and playground toggles