11
11
box-sizing : border-box;
12
12
}
13
13
14
+ .visually-hidden {
15
+ position : absolute !important ;
16
+ width : 1px ;
17
+ height : 1px ;
18
+ padding : 0 ;
19
+ margin : -1px ;
20
+ overflow : hidden;
21
+ clip : rect (0 , 0 , 0 , 0 );
22
+ white-space : nowrap;
23
+ border : 0 ;
24
+ }
25
+
26
+ .visually-hidden .focusable : active ,
27
+ .visually-hidden .focusable : focus {
28
+ position : static !important ;
29
+ width : auto;
30
+ height : auto;
31
+ margin : 0 ;
32
+ overflow : visible;
33
+ clip : auto;
34
+ white-space : normal;
35
+ }
36
+
14
37
body {
15
38
font-family : -apple-system, BlinkMacSystemFont, 'Segoe UI' , Roboto, sans-serif;
16
39
background : linear-gradient (135deg , # 667eea 0% , # 764ba2 100% );
211
234
</ style >
212
235
</ head >
213
236
< body >
237
+ < a href ="#friday " class ="visually-hidden focusable "> Skip to main content</ a >
214
238
< div class ="container ">
215
239
< div class ="header ">
216
240
< h1 > Open Sauce 2025</ h1 >
217
241
< p > July 18-20, 2025</ p >
218
- < button class ="download-btn " onclick ="downloadICS() "> 📅 Download Calendar (ICS)</ button >
242
+ < button class ="download-btn " onclick ="downloadICS() " aria-label =" Download calendar in ICS format " > 📅 Download Calendar (ICS)</ button >
219
243
</ div >
220
244
221
- < div class ="day-tabs ">
222
- < button class ="day-tab active " onclick ="showDay('friday') "> Friday 18th</ button >
223
- < button class ="day-tab " onclick ="showDay('saturday') "> Saturday 19th</ button >
224
- < button class ="day-tab " onclick ="showDay('sunday') "> Sunday 20th</ button >
245
+ < div class ="day-tabs " role =" tablist " >
246
+ < button id =" tab-friday " class ="day-tab active " role =" tab " aria-controls =" friday " aria-selected =" true " onclick ="showDay('friday', event ) "> Friday 18th</ button >
247
+ < button id =" tab-saturday " class ="day-tab " role =" tab " aria-controls =" saturday " aria-selected =" false " tabindex =" -1 " onclick ="showDay('saturday', event ) "> Saturday 19th</ button >
248
+ < button id =" tab-sunday " class ="day-tab " role =" tab " aria-controls =" sunday " aria-selected =" false " tabindex =" -1 " onclick ="showDay('sunday', event ) "> Sunday 20th</ button >
225
249
</ div >
226
250
227
- < div class ="loading " id ="loading "> Loading schedule...</ div >
251
+ < div class ="loading " id ="loading " role =" status " aria-live =" polite " > Loading schedule...</ div >
228
252
229
- < div id ="friday " class ="day-content active "> </ div >
230
- < div id ="saturday " class ="day-content "> </ div >
231
- < div id ="sunday " class ="day-content "> </ div >
253
+ < div id ="friday " class ="day-content active " role =" tabpanel " aria-labelledby =" tab-friday " > </ div >
254
+ < div id ="saturday " class ="day-content " role =" tabpanel " aria-labelledby =" tab-saturday " aria-hidden =" true " > </ div >
255
+ < div id ="sunday " class ="day-content " role =" tabpanel " aria-labelledby =" tab-sunday " aria-hidden =" true " > </ div >
232
256
</ div >
233
257
234
258
< script >
@@ -266,7 +290,7 @@ <h1>Open Sauce 2025</h1>
266
290
</div>
267
291
<div class="session-location">${ session . where } </div>
268
292
</div>
269
- <div class="session-title">${ session . title } </div >
293
+ <h3 class="session-title">${ session . title } </h3 >
270
294
<div class="session-description">${ session . description } </div>
271
295
${ session . speakers && session . speakers . length > 0 ? `
272
296
<div class="speakers">
@@ -289,22 +313,31 @@ <h1>Open Sauce 2025</h1>
289
313
} ) ;
290
314
}
291
315
292
- function showDay ( day ) {
316
+ function showDay ( day , e ) {
293
317
// Hide all day contents
294
318
document . querySelectorAll ( '.day-content' ) . forEach ( content => {
295
319
content . classList . remove ( 'active' ) ;
320
+ content . setAttribute ( 'aria-hidden' , 'true' ) ;
296
321
} ) ;
297
-
298
- // Remove active class from all tabs
322
+
323
+ // Update all tabs
299
324
document . querySelectorAll ( '.day-tab' ) . forEach ( tab => {
300
325
tab . classList . remove ( 'active' ) ;
326
+ tab . setAttribute ( 'aria-selected' , 'false' ) ;
327
+ tab . setAttribute ( 'tabindex' , '-1' ) ;
301
328
} ) ;
302
-
329
+
303
330
// Show selected day content
304
- document . getElementById ( day ) . classList . add ( 'active' ) ;
305
-
331
+ const panel = document . getElementById ( day ) ;
332
+ panel . classList . add ( 'active' ) ;
333
+ panel . setAttribute ( 'aria-hidden' , 'false' ) ;
334
+
306
335
// Add active class to clicked tab
307
- event . target . classList . add ( 'active' ) ;
336
+ const tab = e . currentTarget ;
337
+ tab . classList . add ( 'active' ) ;
338
+ tab . setAttribute ( 'aria-selected' , 'true' ) ;
339
+ tab . removeAttribute ( 'tabindex' ) ;
340
+ tab . focus ( ) ;
308
341
}
309
342
310
343
function timeToMinutes ( timeStr ) {
0 commit comments