diff --git a/packages/components/tabs/src/Tabs.doc.mdx b/packages/components/tabs/src/Tabs.doc.mdx index 573e283959..5de42a8394 100644 --- a/packages/components/tabs/src/Tabs.doc.mdx +++ b/packages/components/tabs/src/Tabs.doc.mdx @@ -86,6 +86,14 @@ Use `size` prop to set the size of items. +### keepMountedOnInactive + +Use `keepMountedOnInactive` when you want the content of your inactive tabs to remain in the DOM instead of being removed. + +This can be useful if your tabs load heavy resources on mount, such as heavy images, videos, iframes, etc... + + + ## Accessibility Adheres to the [Tabs WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs). diff --git a/packages/components/tabs/src/Tabs.stories.tsx b/packages/components/tabs/src/Tabs.stories.tsx index 9d0b9fe4c3..e3566b8f69 100644 --- a/packages/components/tabs/src/Tabs.stories.tsx +++ b/packages/components/tabs/src/Tabs.stories.tsx @@ -263,6 +263,16 @@ export const Size: StoryFn = _args => ( ) +export const KeepMountedOnInactive: StoryFn = _args => ( +
+ keepMountedOnInactive + {createTabs({ + rootProps: { defaultValue: 'tab1', keepMountedOnInactive: true }, + tabs: defaultTabs, + })} +
+) + export const State: StoryFn = _args => (
diff --git a/packages/components/tabs/src/Tabs.test.tsx b/packages/components/tabs/src/Tabs.test.tsx index bd9c9f547f..4c351a90eb 100644 --- a/packages/components/tabs/src/Tabs.test.tsx +++ b/packages/components/tabs/src/Tabs.test.tsx @@ -209,6 +209,19 @@ describe('Tabs', () => { behavior: 'smooth', }) }) + + it('should keep inactive tabs in the DOM (but hidden) when keepMountedOnInactive prop is true', async () => { + render( + createTabs({ + tabs, + rootProps: { defaultValue: 'tab1', keepMountedOnInactive: true }, + }) + ) + + expect(screen.getByText(/Make things happen!/)).toBeInTheDocument() + + expect(screen.getAllByRole('tabpanel').at(-1)).toHaveClass('data-[state=inactive]:hidden') + }) }) }) }) diff --git a/packages/components/tabs/src/Tabs.tsx b/packages/components/tabs/src/Tabs.tsx index 527cc59fb1..48732391fc 100644 --- a/packages/components/tabs/src/Tabs.tsx +++ b/packages/components/tabs/src/Tabs.tsx @@ -13,6 +13,11 @@ export interface TabsProps * @default false */ asChild?: boolean + /** + * Whether to keep inactive tabs content in the DOM. + * @default false + */ + keepMountedOnInactive?: boolean } /** @@ -30,6 +35,7 @@ export const Tabs = forwardRef( * see https://www.radix-ui.com/docs/primitives/components/tabs#root */ asChild = false, + keepMountedOnInactive = false, orientation = 'horizontal', children, className, @@ -43,6 +49,7 @@ export const Tabs = forwardRef( intent, size, orientation, + keepMountedOnInactive, }} > > { @@ -34,10 +35,13 @@ export const TabsContent = forwardRef( }, ref ) => { + const { keepMountedOnInactive } = useTabsContext() + return ( diff --git a/packages/components/tabs/src/TabsContext.tsx b/packages/components/tabs/src/TabsContext.tsx index 22556dcbb5..f44d590b58 100644 --- a/packages/components/tabs/src/TabsContext.tsx +++ b/packages/components/tabs/src/TabsContext.tsx @@ -3,7 +3,8 @@ import { createContext, useContext } from 'react' import type { TabsTriggerVariantsProps } from './TabsTrigger.styles' -export type TabsContextInterface = TabsTriggerVariantsProps & Pick +export type TabsContextInterface = TabsTriggerVariantsProps & + Pick & { keepMountedOnInactive?: boolean } export const TabsContext = createContext({} as TabsContextInterface)