Repository: elastic/eui (TypeScript)

Issue:
[EuiDataGrid] When in memory sorting is enabled the grid zebra stripes do not render properly
**Describe the bug**
I have a table with one numeric and string field. When I don't sort the stripes are rendered correctly. 

When I am sorting then it doesn't. Check the stripes on the second screenshot and you will see that they are not rendered correctly.

**No sorting**
<img width="1181" alt="image" src="https://github.com/elastic/eui/assets/17003240/bb8fbf40-b97d-4517-9535-4b93482d092c">

**Sorting**
<img width="1194" alt="image" src="https://github.com/elastic/eui/assets/17003240/fc92e16c-546e-4955-a454-4fd4f6aa0c80">

**Impact and severity**
It is just a UI problem

**Environment and versions**
- EUI version: 89.0.0
- Kibana version (if applicable): 8.11 (and current main)
- Browser: Chrome



Fix (patch):
diff --git a/src/components/datagrid/body/data_grid_row_manager.ts b/src/components/datagrid/body/data_grid_row_manager.ts
index 090f4b49365..05984951216 100644
--- a/src/components/datagrid/body/data_grid_row_manager.ts
+++ b/src/components/datagrid/body/data_grid_row_manager.ts
@@ -6,7 +6,9 @@
  * Side Public License, v 1.
  */
 
-import { useRef, useCallback, useEffect, RefObject } from 'react';
+import { useRef, useCallback, RefObject } from 'react';
+import { useUpdateEffect } from '../../../services';
+
 import { EuiDataGridRowManager, EuiDataGridStyle } from '../data_grid_types';
 
 export const useRowManager = ({
@@ -25,14 +27,11 @@ export const useRowManager = ({
       if (rowElement == null) {
         rowElement = document.createElement('div');
         rowElement.setAttribute('role', 'row');
-        rowElement.dataset.gridRowIndex = String(rowIndex); // Row index from data, affected by sorting/pagination
-        rowElement.dataset.gridVisibleRowIndex = String(visibleRowIndex); // Affected by sorting/pagination
+        rowElement.dataset.gridRowIndex = String(rowIndex); // Row index from data, not affected by sorting/pagination
         rowElement.classList.add('euiDataGridRow');
         if (rowClasses?.[rowIndex]) {
-          rowElement.classList.add(rowClasses[rowIndex]);
+          rowElement.classList.add(...rowClasses[rowIndex].split(' '));
         }
-        const isOddRow = visibleRowIndex % 2 !== 0;
-        if (isOddRow) rowElement.classList.add('euiDataGridRow--striped');
         rowElement.style.position = 'absolute';
         rowElement.style.left = '0';
         rowElement.style.right = '0';
@@ -58,6 +57,17 @@ export const useRowManager = ({
         observer.observe(rowElement, { childList: true });
       }
 
+      // Ensure the row's visible row index & striping update correctly on sort & pagination
+      if (rowElement.dataset.gridVisibleRowIndex !== String(visibleRowIndex)) {
+        rowElement.dataset.gridVisibleRowIndex = String(visibleRowIndex);
+        const isOddRow = visibleRowIndex % 2 !== 0;
+        if (isOddRow) {
+          rowElement.classList.add('euiDataGridRow--striped');
+        } else {
+          rowElement.classList.remove('euiDataGridRow--striped');
+        }
+      }
+
       // Ensure that the row's dimensions are always correct by having each cell update position styles
       rowElement.style.top = top;
       rowElement.style.height = `${height}px`;
@@ -68,13 +78,17 @@ export const useRowManager = ({
   );
 
   // Update row classes dynamically whenever a new prop is passed in
-  useEffect(() => {
+  useUpdateEffect(() => {
     if (rowClasses) {
       rowIdToElements.current.forEach((rowElement, rowIndex) => {
+        const euiClasses = Array.from(rowElement.classList)
+          .filter((className) => className.startsWith('euiDataGridRow'))
+          .join(' ');
+
         if (rowClasses[rowIndex]) {
-          rowElement.classList.value = `euiDataGridRow ${rowClasses[rowIndex]}`;
+          rowElement.classList.value = `${euiClasses} ${rowClasses[rowIndex]}`;
         } else {
-          rowElement.classList.value = 'euiDataGridRow'; // Clear any added classes
+          rowElement.classList.value = euiClasses; // Clear any added classes
         }
       });
     }
diff --git a/upcoming_changelogs/7301.md b/upcoming_changelogs/7301.md
new file mode 100644
index 00000000000..c6e239d6f8b
--- /dev/null
+++ b/upcoming_changelogs/7301.md
@@ -0,0 +1,5 @@
+**Bug fixes**
+
+- Fixed `EuiDataGrid`s with `gridStyle.stripes` sometimes showing buggy row striping after being sorted
+- Fixed `EuiDataGrid`'s `gridStyle.rowClasses` API to not conflict with `gridStyle.stripes` if dynamically updated
+- Fixed `EuiDataGrid`'s `gridStyle.rowClasses` API to support multiple space-separated classes