@@ -32,7 +32,7 @@ import {
3232} from '@lumino/signaling' ;
3333
3434import {
35- ElementDataset , ElementInlineStyle , VirtualDOM , VirtualElement , h
35+ ElementARIAAttrs , ElementDataset , ElementInlineStyle , VirtualDOM , VirtualElement , h
3636} from '@lumino/virtualdom' ;
3737
3838import {
@@ -65,15 +65,16 @@ class TabBar<T> extends Widget {
6565 /* <DEPRECATED> */
6666 this . addClass ( 'p-TabBar' ) ;
6767 /* </DEPRECATED> */
68+ this . contentNode . setAttribute ( 'role' , 'tablist' ) ;
6869 this . setFlag ( Widget . Flag . DisallowLayout ) ;
6970 this . tabsMovable = options . tabsMovable || false ;
7071 this . titlesEditable = options . titlesEditable || false ;
7172 this . allowDeselect = options . allowDeselect || false ;
7273 this . insertBehavior = options . insertBehavior || 'select-tab-if-needed' ;
74+ this . name = options . name || '' ;
75+ this . orientation = options . orientation || 'horizontal' ;
7376 this . removeBehavior = options . removeBehavior || 'select-tab-after' ;
7477 this . renderer = options . renderer || TabBar . defaultRenderer ;
75- this . _orientation = options . orientation || 'horizontal' ;
76- this . dataset [ 'orientation' ] = this . _orientation ;
7778 }
7879
7980 /**
@@ -268,6 +269,25 @@ class TabBar<T> extends Widget {
268269 } ) ;
269270 }
270271
272+ /**
273+ * Get the name of the tab bar.
274+ */
275+ get name ( ) : string {
276+ return this . _name ;
277+ }
278+
279+ /**
280+ * Set the name of the tab bar.
281+ */
282+ set name ( value : string ) {
283+ this . _name = value ;
284+ if ( value ) {
285+ this . contentNode . setAttribute ( 'aria-label' , value ) ;
286+ } else {
287+ this . contentNode . removeAttribute ( 'aria-label' ) ;
288+ }
289+ }
290+
271291 /**
272292 * Get the orientation of the tab bar.
273293 *
@@ -296,6 +316,7 @@ class TabBar<T> extends Widget {
296316 // Toggle the orientation values.
297317 this . _orientation = value ;
298318 this . dataset [ 'orientation' ] = value ;
319+ this . contentNode . setAttribute ( 'aria-orientation' , value ) ;
299320 }
300321
301322 /**
@@ -997,6 +1018,9 @@ class TabBar<T> extends Widget {
9971018 let ci = this . _currentIndex ;
9981019 let bh = this . insertBehavior ;
9991020
1021+
1022+ // TODO: do we need to do an update to update the aria-selected attribute?
1023+
10001024 // Handle the behavior where the new tab is always selected,
10011025 // or the behavior where the new tab is selected if needed.
10021026 if ( bh === 'select-tab' || ( bh === 'select-tab-if-needed' && ci === - 1 ) ) {
@@ -1050,6 +1074,8 @@ class TabBar<T> extends Widget {
10501074 return ;
10511075 }
10521076
1077+ // TODO: do we need to do an update to adjust the aria-selected value?
1078+
10531079 // No tab gets selected if the tab bar is empty.
10541080 if ( this . _titles . length === 0 ) {
10551081 this . _currentIndex = - 1 ;
@@ -1110,6 +1136,7 @@ class TabBar<T> extends Widget {
11101136 this . update ( ) ;
11111137 }
11121138
1139+ private _name : string ;
11131140 private _currentIndex = - 1 ;
11141141 private _titles : Title < T > [ ] = [ ] ;
11151142 private _orientation : TabBar . Orientation ;
@@ -1201,6 +1228,13 @@ namespace TabBar {
12011228 */
12021229 export
12031230 interface IOptions < T > {
1231+ /**
1232+ * Name of the tab bar.
1233+ *
1234+ * This is used for accessibility reasons. The default is the empty string.
1235+ */
1236+ name ?: string ;
1237+
12041238 /**
12051239 * The layout orientation of the tab bar.
12061240 *
@@ -1430,11 +1464,13 @@ namespace TabBar {
14301464 renderTab ( data : IRenderData < any > ) : VirtualElement {
14311465 let title = data . title . caption ;
14321466 let key = this . createTabKey ( data ) ;
1467+ let id = key ;
14331468 let style = this . createTabStyle ( data ) ;
14341469 let className = this . createTabClass ( data ) ;
14351470 let dataset = this . createTabDataset ( data ) ;
1471+ let aria = this . createTabARIA ( data ) ;
14361472 return (
1437- h . li ( { key, className, title, style, dataset } ,
1473+ h . li ( { id , key, className, title, style, dataset, ... aria } ,
14381474 this . renderIcon ( data ) ,
14391475 this . renderLabel ( data ) ,
14401476 this . renderCloseIcon ( data )
@@ -1568,6 +1604,17 @@ namespace TabBar {
15681604 return data . title . dataset ;
15691605 }
15701606
1607+ /**
1608+ * Create the ARIA attributes for a tab.
1609+ *
1610+ * @param data - The data to use for the tab.
1611+ *
1612+ * @returns The ARIA attributes for the tab.
1613+ */
1614+ createTabARIA ( data : IRenderData < any > ) : ElementARIAAttrs {
1615+ return { role : 'tab' , 'aria-selected' : data . current . toString ( ) } ;
1616+ }
1617+
15711618 /**
15721619 * Create the class name for the tab icon.
15731620 *
@@ -1730,6 +1777,7 @@ namespace Private {
17301777 function createNode ( ) : HTMLDivElement {
17311778 let node = document . createElement ( 'div' ) ;
17321779 let content = document . createElement ( 'ul' ) ;
1780+ content . setAttribute ( 'role' , 'tablist' ) ;
17331781 content . className = 'lm-TabBar-content' ;
17341782 /* <DEPRECATED> */
17351783 content . classList . add ( 'p-TabBar-content' ) ;
0 commit comments