@@ -6,6 +6,7 @@ import React, {
66 ReactNode ,
77 Ref ,
88 createContext ,
9+ useId ,
910 useContext ,
1011 useMemo ,
1112 useRef ,
@@ -45,8 +46,21 @@ const TabsActiveKeyContext = createContext<TabKey | undefined>(undefined);
4546const TabsContext = createContext < {
4647 type : TabType ;
4748 activeTabRef ?: Ref < HTMLAnchorElement > ;
49+ tabIdPrefix ?: string ;
50+ tabItemIdPrefix ?: string ;
4851} > ( { type : 'default' } ) ;
4952
53+ /**
54+ * Custom hook to generate unique tab IDs
55+ */
56+ const useTabIds = ( eventKey ?: TabKey ) => {
57+ const { tabIdPrefix, tabItemIdPrefix } = useContext ( TabsContext ) ;
58+ const tabIndex = eventKey ? String ( eventKey ) : '0' ;
59+ const tabId = `${ tabIdPrefix } -${ tabIndex } ` ;
60+ const tabItemId = `${ tabItemIdPrefix } -${ tabIndex } ` ;
61+ return { tabId, tabItemId } ;
62+ } ;
63+
5064/**
5165 *
5266 */
@@ -59,9 +73,10 @@ export type TabContentProps = {
5973 */
6074const TabContent : FC < TabContentProps > = ( props ) => {
6175 const { className, active, children, ...rprops } = props ;
76+ const { type } = useContext ( TabsContext ) ;
6277 const tabClassNames = classnames (
6378 className ,
64- ' slds-tabs__content' ,
79+ ` slds-tabs_ ${ type } __content` ,
6580 `slds-${ active ? 'show' : 'hide' } `
6681 ) ;
6782 return (
@@ -143,6 +158,7 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
143158 const { type, activeTabRef } = useContext ( TabsContext ) ;
144159 const activeKey = useContext ( TabsActiveKeyContext ) ;
145160 const { onTabClick, onTabKeyDown } = useContext ( TabsHandlersContext ) ;
161+ const { tabId, tabItemId } = useTabIds ( eventKey ) ;
146162 let { menuItems } = props ;
147163 menuItems = menu
148164 ? React . Children . toArray (
@@ -152,9 +168,9 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
152168 const menuProps = ( menu ?. props as unknown ) ?? { } ;
153169 const isActive = eventKey === activeKey ;
154170 const tabItemClassName = classnames (
155- { ' slds-tabs__item' : ! ! menuItems } ,
171+ 'react- slds-tab-item' ,
156172 `slds-tabs_${ type } __item` ,
157- { 'slds-active' : isActive } ,
173+ { 'slds-is- active' : isActive } ,
158174 { 'react-slds-tab-with-menu' : menu || menuItems }
159175 ) ;
160176 const tabLinkClassName = `slds-tabs_${ type } __link` ;
@@ -173,19 +189,21 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
173189 onTabKeyDown,
174190 } as RendererProps ;
175191 return (
176- < li className = { tabItemClassName } role = 'presentation' >
192+ < li className = { tabItemClassName } title = { title } role = 'presentation' >
177193 < TabItemRenderer { ...itemRendererProps } >
178194 < span
179195 className = { `react-slds-tab-item-content ${
180196 tooltip ? 'react-slds-tooltip-enabled' : ''
181197 } `}
182198 >
183199 < a
200+ id = { tabItemId }
184201 className = { tabLinkClassName }
185202 role = 'tab'
186203 ref = { isActive ? activeTabRef : undefined }
187204 tabIndex = { isActive ? 0 : - 1 }
188205 aria-selected = { isActive }
206+ aria-controls = { tabId }
189207 onClick = {
190208 eventKey != null ? ( ) => onTabClick ?.( eventKey ) : undefined
191209 }
@@ -244,10 +262,13 @@ export const Tab = <
244262) => {
245263 const { className, eventKey, children } = props ;
246264 const activeKey = useContext ( TabsActiveKeyContext ) ;
265+ const { tabId, tabItemId } = useTabIds ( eventKey ) ;
247266 return (
248267 < TabContent
268+ id = { tabId }
249269 className = { className }
250270 active = { eventKey != null && eventKey === activeKey }
271+ aria-labelledby = { tabItemId }
251272 >
252273 { children }
253274 </ TabContent >
@@ -273,34 +294,34 @@ function useInitComponentStyle() {
273294 useEffect ( ( ) => {
274295 registerStyle ( 'tab-menu' , [
275296 [
276- '.slds-tabs__item .react-slds-tab-with-menu' ,
297+ '.react- slds-tab-item .react-slds-tab-with-menu' ,
277298 '{ position: relative !important; overflow: visible !important; }' ,
278299 ] ,
279300 [
280- '.slds-tabs__item .react-slds-tab-with-menu > .react-slds-tab-item-content' ,
301+ '.react- slds-tab-item .react-slds-tab-with-menu > .react-slds-tab-item-content' ,
281302 '{ overflow: hidden }' ,
282303 ] ,
283304 [
284- '.slds-tabs__item .react-slds-tab-with-menu > .react-slds-tab-item-content > a' ,
305+ '.react- slds-tab-item .react-slds-tab-with-menu > .react-slds-tab-item-content > a' ,
285306 '{ padding-right: 2rem; }' ,
286307 ] ,
287308 [
288- '.slds-tabs__item .react-slds-tab-with-menu > .react-slds-tab-item-content.react-slds-tooltip-enabled > a' ,
309+ '.react- slds-tab-item .react-slds-tab-with-menu > .react-slds-tab-item-content.react-slds-tooltip-enabled > a' ,
289310 '{ padding-right: 3.5rem; }' ,
290311 ] ,
291312 [ '.react-slds-tab-menu' , '{ position: absolute; top: 0; right: 0; }' ] ,
292313 [
293- '.slds-tabs__item .react-slds-tab-with-menu .react-slds-tab-item-content .react-slds-tooltip-content' ,
314+ '.react- slds-tab-item .react-slds-tab-with-menu .react-slds-tab-item-content .react-slds-tooltip-content' ,
294315 '{ position: absolute; top: 0.6rem; right: 2.25rem; }' ,
295316 ] ,
296317 [
297318 '.react-slds-tab-menu button' ,
298319 '{ height: 2.5rem; line-height: 2rem; width: 2rem; visibility: hidden; justify-content: center }' ,
299320 ] ,
300321 [
301- '.slds-tabs__item .slds-active .react-slds-tab-menu button' ,
302- '.slds-tabs__item :hover .react-slds-tab-menu button' ,
303- '.slds-tabs__item .react-slds-tab-menu button:focus' ,
322+ '.react- slds-tab-item .slds-is -active .react-slds-tab-menu button' ,
323+ '.react- slds-tab-item :hover .react-slds-tab-menu button' ,
324+ '.react- slds-tab-item .react-slds-tab-menu button:focus' ,
304325 '{ visibility: visible }' ,
305326 ] ,
306327 ] ) ;
@@ -369,7 +390,13 @@ export const Tabs: FC<TabsProps> = (props) => {
369390 }
370391 } , [ focusTab ] ) ;
371392
372- const tabCtx = useMemo ( ( ) => ( { type, activeTabRef } ) , [ type ] ) ;
393+ const tabIdPrefix = useId ( ) ;
394+ const tabItemIdPrefix = useId ( ) ;
395+ const tabCtx = useMemo (
396+ ( ) => ( { type, activeTabRef, tabIdPrefix, tabItemIdPrefix } ) ,
397+ [ type , tabIdPrefix , tabItemIdPrefix ]
398+ ) ;
399+
373400 const handlers = useMemo (
374401 ( ) => ( { onTabClick, onTabKeyDown } ) ,
375402 [ onTabClick , onTabKeyDown ]
0 commit comments