Skip to content

Conversation

@mgadewoll
Copy link
Contributor

@mgadewoll mgadewoll commented Dec 18, 2025

Summary

Closes https://github.com/elastic/eui-private/issues/475
Closes #9000

This PR updates EuiDataGrid to add support for a conditionally rendered header element via a new prop: headerVisibility. The naming is chosen to be in line with the existing toolbarVisibility for the external facing API.

prop type default value description
headerVisibility boolean true Controls if the datagrid header element is rendered or not

Accessibility

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 EuiDataGrid adds 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
light dark
Screenshot 2025-12-18 at 15 08 55 Screenshot 2025-12-18 at 15 08 58

Usage with headerVisibility=false + toolbarVisibility=false

light dark
Screenshot 2025-12-18 at 12 46 33 Screenshot 2025-12-18 at 12 46 29

Impact to users

🟢 No updates required on consumer side. This is a new, opt-in feature.

QA

  • test the new headerVisibility on EuiDataGrid and verify it works as expected (ensure to test in different combinations: with toolbarvisibility with different border styles etc
  • verify there is otherwise no regression with production
  • verify that cells have the correct contextual header information appended for screen readers

General checklist

  • Browser QA
    • Checked in both light and dark modes
    • Checked in both MacOS and Windows high contrast modes
    • Checked in mobile
    • Checked in Chrome, Safari, Edge, and Firefox
    • Checked for accessibility including keyboard-only and screenreader modes
  • Docs site QA
  • Code quality checklist
  • Release checklist
    • A changelog entry exists and is marked appropriately
    • If applicable, added the breaking change issue label (and filled out the breaking change checklist)
    • If the changes unblock an issue in a different repo, smoke tested carefully (see Testing EUI features in Kibana ahead of time)
  • Designer checklist
    • If applicable, file an issue to update EUI's Figma library with any corresponding UI changes. (This is an internal repo, if you are external to Elastic, ask a maintainer to submit this request)

@mgadewoll mgadewoll self-assigned this Dec 18, 2025
@mgadewoll mgadewoll force-pushed the datagrid/optional-header branch 2 times, most recently from 33a1a55 to 92feee7 Compare December 18, 2025 14:24
@mgadewoll mgadewoll force-pushed the datagrid/optional-header branch from 92feee7 to be49e96 Compare December 18, 2025 17:04
@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @mgadewoll

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @mgadewoll

@mgadewoll mgadewoll marked this pull request as ready for review December 19, 2025 10:00
@mgadewoll mgadewoll requested a review from a team as a code owner December 19, 2025 10:00
Comment on lines +22 to +28
/* hack to prevent visible flickering on the single initial render when rows are created.
opacity > 0 ensure the element is anyway present in the DOM */
.euiDataGridRowCell--isMounting:where(
:not(.euiDataGridHeaderCell, .euiDataGridFooterCell)
) {
opacity: 0.01;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't reproduce any flickering on the initial render. Could you provide more details how to test this?

If the change is not related to the conditional rendering of the header in any way (e.g. it doesn't make the flickering issue significantly worse), I'd extract it to a separate PR with an appropriate description, steps to reproduce, pointers what to test for and a link to related issues (if they exist).

const wrapperDimensions = useResizeObserver(wrapperRef.current);
const outerGridRef = useRef<HTMLDivElement | null>(null); // container that becomes scrollable
const innerGridRef = useRef<HTMLDivElement | null>(null); // container sized to fit all content
const innerGridRef = useRef<HTMLDivElement | null>(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this comment removed?

Copy link
Contributor

@weronikaolejniczak weronikaolejniczak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Image Image
Dark mode Image Image

✅ default headerVisiblity={true} & toolbarVisibility={false}

HCM off HCM on
Light mode Image Image
Dark mode Image Image

headerVisiblity={false} & toolbarVisibility={false}

HCM off HCM on
Light mode Image Image
Dark mode Image Image

headerVisiblity={false} & default toolbarVisibility

HCM off HCM on
Light mode Image Image
Dark mode Image Image

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 Image Image
toolbarVisibility={false} Image Image

none

default headerVisibility={true} headerVisibility={false}
default toolbarVisibility Image Image
toolbarVisibility={false} Image Image

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[EuiDataGrid] Create headerless option

3 participants