diff --git a/packages/mui-base/src/Tabs/Root/TabsRoot.tsx b/packages/mui-base/src/Tabs/Root/TabsRoot.tsx
index 85b20c9838..eab967c43c 100644
--- a/packages/mui-base/src/Tabs/Root/TabsRoot.tsx
+++ b/packages/mui-base/src/Tabs/Root/TabsRoot.tsx
@@ -3,10 +3,11 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import { useComponentRenderer } from '../../utils/useComponentRenderer';
import type { BaseUIComponentProps } from '../../utils/types';
-import { CompoundComponentContext } from '../../useCompound';
+import { CompositeList } from '../../Composite/List/CompositeList';
import { useTabsRoot } from './useTabsRoot';
import { TabsRootContext } from './TabsRootContext';
import { tabsStyleHookMapping } from './styleHooks';
+import { TabPanelMetadata } from '../TabPanel/useTabPanel';
/**
*
@@ -35,13 +36,14 @@ const TabsRoot = React.forwardRef(function TabsRoot(
const {
getRootProps,
- compoundContext,
direction,
getTabId,
- getTabPanelId,
+ getTabPanelIdByTabValueOrIndex,
onSelected,
registerTabIdLookup,
+ setTabPanelMap,
tabActivationDirection,
+ tabPanelRefs,
value,
} = useTabsRoot({
value: valueProp,
@@ -54,7 +56,7 @@ const TabsRoot = React.forwardRef(function TabsRoot(
() => ({
direction,
getTabId,
- getTabPanelId,
+ getTabPanelIdByTabValueOrIndex,
onSelected,
orientation,
registerTabIdLookup,
@@ -64,7 +66,7 @@ const TabsRoot = React.forwardRef(function TabsRoot(
[
direction,
getTabId,
- getTabPanelId,
+ getTabPanelIdByTabValueOrIndex,
onSelected,
orientation,
registerTabIdLookup,
@@ -90,11 +92,11 @@ const TabsRoot = React.forwardRef(function TabsRoot(
});
return (
-
-
+
+ elementsRef={tabPanelRefs} onMapChange={setTabPanelMap}>
{renderElement()}
-
-
+
+
);
});
diff --git a/packages/mui-base/src/Tabs/Root/TabsRootContext.ts b/packages/mui-base/src/Tabs/Root/TabsRootContext.ts
index dc910dae43..22df27ba6c 100644
--- a/packages/mui-base/src/Tabs/Root/TabsRootContext.ts
+++ b/packages/mui-base/src/Tabs/Root/TabsRootContext.ts
@@ -36,7 +36,7 @@ export interface TabsRootContext {
* Gets the id of the tab panel with the given value.
* @param value Value to find the tab panel for.
*/
- getTabPanelId: (value: any) => string | undefined;
+ getTabPanelIdByTabValueOrIndex: (tabValue: any, index: number) => string | undefined;
/**
* The position of the active tab relative to the previously active tab.
*/
diff --git a/packages/mui-base/src/Tabs/Root/useTabsRoot.ts b/packages/mui-base/src/Tabs/Root/useTabsRoot.ts
index a1cf908be6..20cd527939 100644
--- a/packages/mui-base/src/Tabs/Root/useTabsRoot.ts
+++ b/packages/mui-base/src/Tabs/Root/useTabsRoot.ts
@@ -1,14 +1,9 @@
'use client';
import * as React from 'react';
-import type { TabActivationDirection } from './TabsRoot';
-import { CompoundComponentContextValue, useCompoundParent } from '../../useCompound';
import { mergeReactProps } from '../../utils/mergeReactProps';
import { useControlled } from '../../utils/useControlled';
-
-interface TabPanelMetadata {
- id: string | undefined;
- ref: React.RefObject;
-}
+import type { TabPanelMetadata } from '../TabPanel/useTabPanel';
+import type { TabActivationDirection } from './TabsRoot';
export interface TabMetadata {
disabled: boolean;
@@ -21,6 +16,9 @@ type IdLookupFunction = (id: any) => string | undefined;
function useTabsRoot(parameters: useTabsRoot.Parameters): useTabsRoot.ReturnValue {
const { value: valueProp, defaultValue, onValueChange, direction = 'ltr' } = parameters;
+ const tabPanelRefs = React.useRef<(HTMLElement | null)[]>([]);
+ const getTabIdByPanelValueRef = React.useRef(() => undefined);
+
const [value, setValue] = useControlled({
controlled: valueProp,
default: defaultValue,
@@ -28,6 +26,10 @@ function useTabsRoot(parameters: useTabsRoot.Parameters): useTabsRoot.ReturnValu
state: 'value',
});
+ const [tabPanelMap, setTabPanelMap] = React.useState(
+ () => new Map(),
+ );
+
const [tabActivationDirection, setTabActivationDirection] =
React.useState('none');
@@ -44,26 +46,39 @@ function useTabsRoot(parameters: useTabsRoot.Parameters): useTabsRoot.ReturnValu
[onValueChange, setValue],
);
- const { subitems: tabPanels, contextValue: compoundComponentContextValue } = useCompoundParent<
- any,
- TabPanelMetadata
- >();
-
- const tabIdLookup = React.useRef(() => undefined);
-
- const getTabPanelId = React.useCallback(
- (tabValue: any) => {
- return tabPanels.get(tabValue)?.id;
+ const getTabPanelIdByTabValueOrIndex = React.useCallback(
+ (tabValue: any | undefined, index: number) => {
+ if (tabValue === undefined && index < 0) {
+ return undefined;
+ }
+
+ for (const tabPanelMetadata of tabPanelMap.values()) {
+ // find by tabValue
+ if (tabValue !== undefined && tabPanelMetadata && tabValue === tabPanelMetadata?.value) {
+ return tabPanelMetadata.id;
+ }
+
+ // find by index
+ if (
+ tabValue === undefined &&
+ tabPanelMetadata?.index &&
+ tabPanelMetadata?.index === index
+ ) {
+ return tabPanelMetadata.id;
+ }
+ }
+
+ return undefined;
},
- [tabPanels],
+ [tabPanelMap],
);
- const getTabId = React.useCallback((tabPanelId: any) => {
- return tabIdLookup.current(tabPanelId);
+ const getTabIdByPanelValue = React.useCallback((tabPanelValue: any) => {
+ return getTabIdByPanelValueRef.current(tabPanelValue);
}, []);
const registerTabIdLookup = React.useCallback((lookupFunction: IdLookupFunction) => {
- tabIdLookup.current = lookupFunction;
+ getTabIdByPanelValueRef.current = lookupFunction;
}, []);
const getRootProps: useTabsRoot.ReturnValue['getRootProps'] = React.useCallback(
@@ -75,14 +90,15 @@ function useTabsRoot(parameters: useTabsRoot.Parameters): useTabsRoot.ReturnValu
);
return {
- compoundContext: compoundComponentContextValue,
getRootProps,
direction,
- getTabId,
- getTabPanelId,
+ getTabId: getTabIdByPanelValue,
+ getTabPanelIdByTabValueOrIndex,
onSelected,
registerTabIdLookup,
+ setTabPanelMap,
tabActivationDirection,
+ tabPanelRefs,
value,
};
}
@@ -113,7 +129,6 @@ namespace useTabsRoot {
getRootProps: (
externalProps?: React.ComponentPropsWithRef<'div'>,
) => React.ComponentPropsWithRef<'div'>;
- compoundContext: CompoundComponentContextValue;
/**
* The direction of the text.
*/
@@ -127,7 +142,10 @@ namespace useTabsRoot {
* Gets the id of the tab panel with the given value.
* @param value Value to find the tab panel for.
*/
- getTabPanelId: (value: any) => string | undefined;
+ getTabPanelIdByTabValueOrIndex: (
+ tabValue: any | undefined,
+ tabIndex: number,
+ ) => string | undefined;
/**
* Callback for setting new value.
@@ -141,10 +159,12 @@ namespace useTabsRoot {
* Registers a function that returns the id of the tab with the given value.
*/
registerTabIdLookup: (lookupFunction: (id: any) => string | undefined) => void;
+ setTabPanelMap: (map: Map) => void;
/**
* The position of the active tab relative to the previously active tab.
*/
tabActivationDirection: TabActivationDirection;
+ tabPanelRefs: React.RefObject<(HTMLElement | null)[]>;
/**
* The currently selected tab's value.
*/
diff --git a/packages/mui-base/src/Tabs/Tab/Tab.test.tsx b/packages/mui-base/src/Tabs/Tab/Tab.test.tsx
index 5a899d1fb5..13815c05d5 100644
--- a/packages/mui-base/src/Tabs/Tab/Tab.test.tsx
+++ b/packages/mui-base/src/Tabs/Tab/Tab.test.tsx
@@ -27,7 +27,7 @@ describe('', () => {
onSelected() {},
registerTabIdLookup() {},
getTabId: () => '',
- getTabPanelId: () => '',
+ getTabPanelIdByTabValueOrIndex: () => '',
orientation: 'horizontal',
direction: 'ltr',
tabActivationDirection: 'none',
diff --git a/packages/mui-base/src/Tabs/Tab/Tab.tsx b/packages/mui-base/src/Tabs/Tab/Tab.tsx
index 805a95aa88..82565f465e 100644
--- a/packages/mui-base/src/Tabs/Tab/Tab.tsx
+++ b/packages/mui-base/src/Tabs/Tab/Tab.tsx
@@ -23,11 +23,15 @@ const Tab = React.forwardRef(function Tab(
) {
const { className, disabled = false, render, value: valueProp, ...other } = props;
- const { value: selectedValue, getTabPanelId, orientation } = useTabsRootContext();
+ const {
+ value: selectedValue,
+ getTabPanelIdByTabValueOrIndex,
+ orientation,
+ } = useTabsRootContext();
const { selected, getRootProps } = useTab({
...props,
- getTabPanelId,
+ getTabPanelIdByTabValueOrIndex,
isSelected: valueProp === selectedValue,
rootRef: forwardedRef,
});
diff --git a/packages/mui-base/src/Tabs/Tab/useTab.test.tsx b/packages/mui-base/src/Tabs/Tab/useTab.test.tsx
index 451f1e6c49..a66721251d 100644
--- a/packages/mui-base/src/Tabs/Tab/useTab.test.tsx
+++ b/packages/mui-base/src/Tabs/Tab/useTab.test.tsx
@@ -15,7 +15,7 @@ describe('useTab', () => {
const { getRootProps } = useTab({
rootRef,
isSelected: true,
- getTabPanelId: () => undefined,
+ getTabPanelIdByTabValueOrIndex: () => undefined,
});
return ;
}
@@ -44,7 +44,7 @@ describe('useTab', () => {
const { getRootProps } = useTab({
rootRef,
isSelected: true,
- getTabPanelId: () => undefined,
+ getTabPanelIdByTabValueOrIndex: () => undefined,
});
return (