diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx
index b5e66fd84a2..f9b7772a5aa 100644
--- a/packages/@react-spectrum/s2/src/TableView.tsx
+++ b/packages/@react-spectrum/s2/src/TableView.tsx
@@ -17,10 +17,12 @@ import {
ButtonContext,
CellRenderProps,
Collection,
+ CollectionRendererContext,
ColumnRenderProps,
ColumnResizer,
ContextValue,
DEFAULT_SLOT,
+ DefaultCollectionRenderer,
Form,
Key,
OverlayTriggerStateContext,
@@ -439,7 +441,9 @@ export const TableBody = /*#__PURE__*/ (forwardRef as forwardRefType)(function T
if (renderEmptyState != null && !isLoading) {
emptyRender = (props: TableBodyRenderProps) => (
- {renderEmptyState(props)}
+
+ {renderEmptyState(props)}
+
);
} else if (loadingState === 'loading') {
diff --git a/packages/@react-spectrum/s2/stories/TableView.stories.tsx b/packages/@react-spectrum/s2/stories/TableView.stories.tsx
index e32ff026983..688bd635bbd 100644
--- a/packages/@react-spectrum/s2/stories/TableView.stories.tsx
+++ b/packages/@react-spectrum/s2/stories/TableView.stories.tsx
@@ -27,21 +27,24 @@ import {
PickerItem,
Row,
StatusLight,
+ Tab,
TableBody,
TableHeader,
TableView,
TableViewProps,
+ TabList,
+ Tabs,
Text,
TextField
} from '../src';
import {categorizeArgTypes, getActionArgs} from './utils';
+import {CollectionRendererContext, DefaultCollectionRenderer, SortDescriptor} from 'react-aria-components';
import Edit from '../s2wf-icons/S2_Icon_Edit_20_N.svg';
import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg';
import FolderOpen from '../spectrum-illustrations/linear/FolderOpen';
import {Key} from '@react-types/shared';
import type {Meta, StoryObj} from '@storybook/react';
import React, {ReactElement, useCallback, useEffect, useRef, useState} from 'react';
-import {SortDescriptor} from 'react-aria-components';
import {style} from '../style/spectrum-theme' with {type: 'macro'};
import {useAsyncList, useListData} from '@react-stately/data';
import {useEffectEvent} from '@react-aria/utils';
@@ -1714,3 +1717,57 @@ export const EditableTableWithAsyncSaving: StoryObj = {
);
}
};
+
+export const TableViewCollectionError: StoryObj = {
+ render: function DynamicColumnsExample() {
+ const columns: Array<{
+ key: string,
+ label: string,
+ align?: 'start' | 'center' | 'end'
+ }> = [
+ {key: 'name', label: 'Name'},
+ {key: 'count', label: 'Count', align: 'end'}
+ ];
+
+ const tabs = [
+ {id: 'general', label: 'General'},
+ {id: 'advanced', label: 'Advanced'},
+ {id: 'about', label: 'About'}
+ ];
+ const renderEmptyState = () => (
+
+ {/* */}
+
+
+ {tabs.map((tab) => (
+
+ {tab.label}
+
+ ))}
+
+
+
+ );
+
+ return (
+
+
+
+ {columns.map((column) => (
+
+ {column.label}
+
+ ))}
+
+
+
+
+ );
+ },
+ args: Example.args,
+ parameters: {
+ docs: {
+ disable: true
+ }
+ }
+};
diff --git a/packages/@react-spectrum/s2/test/TableView.test.tsx b/packages/@react-spectrum/s2/test/TableView.test.tsx
index d00e9980c0a..9b37f5c1d32 100644
--- a/packages/@react-spectrum/s2/test/TableView.test.tsx
+++ b/packages/@react-spectrum/s2/test/TableView.test.tsx
@@ -28,6 +28,7 @@ import {DisabledBehavior} from '@react-types/shared';
import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg';
import {pointerMap, User} from '@react-aria/test-utils';
import React, {useState} from 'react';
+import {Tab, TabList, Tabs} from 'react-aria-components';
import userEvent from '@testing-library/user-event';
// @ts-ignore
@@ -148,4 +149,42 @@ describe('TableView', () => {
await user.tab();
expect(document.activeElement).toBe(cells[3]);
});
+
+ it('should render empty state + nested collection without crashing', async () => {
+ const tabs = [
+ {id: 'general', label: 'General'},
+ {id: 'advanced', label: 'Advanced'}
+ ];
+ const renderEmptyState = () => (
+
+
+ {tabs.map((tab) => (
+
+ {tab.label}
+
+ ))}
+
+
+ );
+
+ let renderResult: ReturnType;
+ await act(async () => {
+ renderResult = render(
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+
+ );
+ await Promise.resolve();
+ });
+ let {getAllByRole} = renderResult!;
+
+ expect(getAllByRole('tab')).toHaveLength(tabs.length);
+ });
});