@@ -32,7 +32,7 @@ import {
32
32
} from '@lumino/signaling' ;
33
33
34
34
import {
35
- ElementDataset , ElementInlineStyle , VirtualDOM , VirtualElement , h
35
+ ElementARIAAttrs , ElementDataset , ElementInlineStyle , VirtualDOM , VirtualElement , h
36
36
} from '@lumino/virtualdom' ;
37
37
38
38
import {
@@ -65,15 +65,16 @@ class TabBar<T> extends Widget {
65
65
/* <DEPRECATED> */
66
66
this . addClass ( 'p-TabBar' ) ;
67
67
/* </DEPRECATED> */
68
+ this . contentNode . setAttribute ( 'role' , 'tablist' ) ;
68
69
this . setFlag ( Widget . Flag . DisallowLayout ) ;
69
70
this . tabsMovable = options . tabsMovable || false ;
70
71
this . titlesEditable = options . titlesEditable || false ;
71
72
this . allowDeselect = options . allowDeselect || false ;
72
73
this . insertBehavior = options . insertBehavior || 'select-tab-if-needed' ;
74
+ this . name = options . name || '' ;
75
+ this . orientation = options . orientation || 'horizontal' ;
73
76
this . removeBehavior = options . removeBehavior || 'select-tab-after' ;
74
77
this . renderer = options . renderer || TabBar . defaultRenderer ;
75
- this . _orientation = options . orientation || 'horizontal' ;
76
- this . dataset [ 'orientation' ] = this . _orientation ;
77
78
}
78
79
79
80
/**
@@ -268,6 +269,25 @@ class TabBar<T> extends Widget {
268
269
} ) ;
269
270
}
270
271
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
+
271
291
/**
272
292
* Get the orientation of the tab bar.
273
293
*
@@ -296,6 +316,7 @@ class TabBar<T> extends Widget {
296
316
// Toggle the orientation values.
297
317
this . _orientation = value ;
298
318
this . dataset [ 'orientation' ] = value ;
319
+ this . contentNode . setAttribute ( 'aria-orientation' , value ) ;
299
320
}
300
321
301
322
/**
@@ -997,6 +1018,9 @@ class TabBar<T> extends Widget {
997
1018
let ci = this . _currentIndex ;
998
1019
let bh = this . insertBehavior ;
999
1020
1021
+
1022
+ // TODO: do we need to do an update to update the aria-selected attribute?
1023
+
1000
1024
// Handle the behavior where the new tab is always selected,
1001
1025
// or the behavior where the new tab is selected if needed.
1002
1026
if ( bh === 'select-tab' || ( bh === 'select-tab-if-needed' && ci === - 1 ) ) {
@@ -1050,6 +1074,8 @@ class TabBar<T> extends Widget {
1050
1074
return ;
1051
1075
}
1052
1076
1077
+ // TODO: do we need to do an update to adjust the aria-selected value?
1078
+
1053
1079
// No tab gets selected if the tab bar is empty.
1054
1080
if ( this . _titles . length === 0 ) {
1055
1081
this . _currentIndex = - 1 ;
@@ -1110,6 +1136,7 @@ class TabBar<T> extends Widget {
1110
1136
this . update ( ) ;
1111
1137
}
1112
1138
1139
+ private _name : string ;
1113
1140
private _currentIndex = - 1 ;
1114
1141
private _titles : Title < T > [ ] = [ ] ;
1115
1142
private _orientation : TabBar . Orientation ;
@@ -1201,6 +1228,13 @@ namespace TabBar {
1201
1228
*/
1202
1229
export
1203
1230
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
+
1204
1238
/**
1205
1239
* The layout orientation of the tab bar.
1206
1240
*
@@ -1430,11 +1464,13 @@ namespace TabBar {
1430
1464
renderTab ( data : IRenderData < any > ) : VirtualElement {
1431
1465
let title = data . title . caption ;
1432
1466
let key = this . createTabKey ( data ) ;
1467
+ let id = key ;
1433
1468
let style = this . createTabStyle ( data ) ;
1434
1469
let className = this . createTabClass ( data ) ;
1435
1470
let dataset = this . createTabDataset ( data ) ;
1471
+ let aria = this . createTabARIA ( data ) ;
1436
1472
return (
1437
- h . li ( { key, className, title, style, dataset } ,
1473
+ h . li ( { id , key, className, title, style, dataset, ... aria } ,
1438
1474
this . renderIcon ( data ) ,
1439
1475
this . renderLabel ( data ) ,
1440
1476
this . renderCloseIcon ( data )
@@ -1568,6 +1604,17 @@ namespace TabBar {
1568
1604
return data . title . dataset ;
1569
1605
}
1570
1606
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
+
1571
1618
/**
1572
1619
* Create the class name for the tab icon.
1573
1620
*
@@ -1730,6 +1777,7 @@ namespace Private {
1730
1777
function createNode ( ) : HTMLDivElement {
1731
1778
let node = document . createElement ( 'div' ) ;
1732
1779
let content = document . createElement ( 'ul' ) ;
1780
+ content . setAttribute ( 'role' , 'tablist' ) ;
1733
1781
content . className = 'lm-TabBar-content' ;
1734
1782
/* <DEPRECATED> */
1735
1783
content . classList . add ( 'p-TabBar-content' ) ;
0 commit comments