-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
188 lines (171 loc) · 10.8 KB
/
index.html
File metadata and controls
188 lines (171 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Table - Resonance Labs</title>
<link rel="stylesheet" href="/resonance-labs/assets/style/global.css" />
<link rel="stylesheet" href="table.css" />
<link rel="icon" href="/resonance-labs/assets/images/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css" />
<script src="/resonance-labs/assets/js/component-layout.js" defer></script>
</head>
<body>
<header><a href="/resonance-labs/index.html" class="back-link"><img src="/resonance-labs/assets/images/logo.svg" alt="Resonance Logo" /></a></header>
<main>
<div class="section">
<h1>Table</h1>
<p class="component-tagline">A table displays structured data in rows and columns, with properly scoped header cells so assistive technology can convey the relationship between each data cell and its headers.</p>
</div>
<div class="section">
<h2>Demo</h2>
<p>Review the table below and use a screen reader to navigate it. Move cell by cell with arrow keys to hear how each data cell is announced together with its column and row header. Try sorting a column if the interaction is available, and note how the sort state is communicated.</p>
<div class="mount"></div>
</div>
<div class="section">
<h2>What to Observe</h2>
<ul>
<li>Each data cell is announced by a screen reader alongside its corresponding column header, providing full context without visual scanning.</li>
<li>The table has a visible caption or a heading immediately preceding it that identifies the data set being presented.</li>
<li>Header cells use the correct scope attribute to declare whether they apply to a column or a row.</li>
<li>If sorting is available, the current sort direction is reflected programmatically so screen readers can announce it.</li>
<li>The table is navigable by keyboard using Tab and arrow keys without any mouse interaction required.</li>
</ul>
</div>
<div class="section">
<h2>Anatomy</h2>
<p class="anatomy-placeholder">[Anatomy image placeholder — will be added when assets are available]</p>
<ol>
<li><strong>Caption:</strong> An optional <code><caption></code> element inside the table that gives the entire table an accessible name describing its contents.</li>
<li><strong>Table head (<code>thead</code>):</strong> The section grouping all column header rows, which browsers and assistive technologies treat differently from data rows.</li>
<li><strong>Header cells (<code>th</code>):</strong> Cells that label a column or row, with a <code>scope</code> attribute set to <code>col</code> or <code>row</code> to define their relationship to data cells.</li>
<li><strong>Table body (<code>tbody</code>):</strong> The section containing all data rows, keeping structure semantic and parseable.</li>
<li><strong>Data cells (<code>td</code>):</strong> Individual cells containing the actual data values, associated with header cells through the table structure.</li>
<li><strong>Sort controls:</strong> Interactive elements within header cells that change column sort order, with <code>aria-sort</code> applied to the active header to communicate current direction.</li>
</ol>
</div>
<div class="section">
<h2>Accessibility Behavior</h2>
<ul>
<li>The table must use native HTML table markup — screen readers rely on the table structure to associate data cells with their headers.</li>
<li>Column and row header cells must carry a <code>scope</code> attribute so assistive technology can announce context for every data cell.</li>
<li>The table must have an accessible name, either through a <code><caption></code> element or an <code>aria-label</code> / <code>aria-labelledby</code> attribute.</li>
<li>If columns are sortable, the active sort column must expose its sort direction through <code>aria-sort</code>, with values of <code>ascending</code> or <code>descending</code>.</li>
<li>All interactive controls within the table, such as sort buttons or row actions, must be reachable and operable by keyboard.</li>
<li>Tables must only be used to present tabular data — never for page layout purposes.</li>
</ul>
</div>
<div class="section">
<h2>Common Mistakes</h2>
<ul>
<li>Using <code><div></code> or CSS grid to visually replicate a table without providing any semantic table markup, making the data meaningless to screen readers.</li>
<li>Omitting the <code>scope</code> attribute on header cells, so assistive technology cannot determine which header belongs to which data cell.</li>
<li>Providing no accessible name for the table, leaving screen reader users without context for what the data represents.</li>
<li>Using a table for visual layout of non-tabular content, which confuses screen readers that announce row and column context.</li>
<li>Adding sort functionality without exposing the current sort state, requiring screen reader users to guess whether or how the data is ordered.</li>
</ul>
</div>
<div class="section">
<h2>Why This Matters</h2>
<p>Tables are one of the most information-dense components on the web, and screen reader users depend entirely on the semantic structure to navigate them. Without proper headers and scope attributes, a screen reader user hears a stream of values with no indication of what column or row each value belongs to. In data-heavy applications — finance dashboards, schedule grids, comparison charts — this makes the content completely unusable. Correct table markup costs no additional effort once the pattern is understood, and it ensures that every user can interpret the data presented to them.</p>
</div>
<div class="section">
<h2>Accessibility Validation</h2>
<p>This component is validated against internal accessibility criteria aligned with WCAG standards, using our internally developed system, <strong>Resonance Specs</strong>.</p>
<p>To learn more, please contact us.</p>
</div>
<div class="section">
<h2>Code</h2>
<div class="code-tabs" role="tablist">
<button class="code-tabs__tab code-tabs__tab--active" role="tab" aria-selected="true" data-tab="html">HTML</button>
<button class="code-tabs__tab" role="tab" aria-selected="false" data-tab="css">CSS</button>
<button class="code-tabs__tab" role="tab" aria-selected="false" data-tab="js">JS</button>
</div>
<div class="code-preview" id="panel-html" role="tabpanel">
<pre class="line-numbers"><code id="code-html" class="language-markup"></code></pre>
<button class="code-preview__copy" data-target="code-html">Copy Code</button>
</div>
<div class="code-preview" id="panel-css" role="tabpanel" hidden>
<pre class="line-numbers"><code id="code-css" class="language-css"></code></pre>
<button class="code-preview__copy" data-target="code-css">Copy Code</button>
</div>
<div class="code-preview" id="panel-js" role="tabpanel" hidden>
<pre class="line-numbers"><code id="code-js" class="language-javascript"></code></pre>
<button class="code-preview__copy" data-target="code-js">Copy Code</button>
</div>
</div>
<div class="section">
<h2>Reference Implementation</h2>
<ul class="btn-group">
<li><a class="btn btn-primary" href="/resonance-labs/index.html">Back to Home</a></li>
<li><a class="btn btn-secondary" href="https://github.com/Accenture/resonance-labs">GitHub Code</a></li>
</ul>
</div>
</main>
<footer>
<p><strong>Created and maintained by Accenture Song</strong></p>
<p>© 2026 Accenture - Resonance</p>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script>
// Fetch HTML fragment
fetch("./table.html")
.then(function (r) { return r.text(); })
.then(function (html) {
document.querySelector(".mount").innerHTML = html;
// Populate HTML code preview (strip leading comment block)
var rawHtml = html.replace(/<!--[\s\S]*?-->\n*/, "").trim();
var codeHtml = document.getElementById("code-html");
codeHtml.textContent = rawHtml;
Prism.highlightElement(codeHtml);
// Load component JS
var s = document.createElement("script");
s.src = "./table.js";
document.body.appendChild(s);
});
// Fetch CSS
fetch("./table.css")
.then(function (r) { return r.text(); })
.then(function (css) {
var codeCss = document.getElementById("code-css");
codeCss.textContent = css;
Prism.highlightElement(codeCss);
});
// Fetch JS
fetch("./table.js")
.then(function (r) { return r.text(); })
.then(function (js) {
var codeJs = document.getElementById("code-js");
codeJs.textContent = js;
Prism.highlightElement(codeJs);
});
// Tab switching
var tabs = document.querySelectorAll(".code-tabs__tab");
var codePanels = document.querySelectorAll("#panel-html, #panel-css, #panel-js");
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("code-tabs__tab--active");
t.setAttribute("aria-selected", "false");
});
codePanels.forEach(function (p) { p.hidden = true; });
tab.classList.add("code-tabs__tab--active");
tab.setAttribute("aria-selected", "true");
document.getElementById("panel-" + tab.dataset.tab).hidden = false;
});
});
// Copy buttons
document.querySelectorAll(".code-preview__copy").forEach(function (btn) {
btn.addEventListener("click", function () {
var codeEl = document.getElementById(btn.dataset.target);
navigator.clipboard.writeText(codeEl.textContent).then(function () {
btn.textContent = "Copied!";
setTimeout(function () { btn.textContent = "Copy Code"; }, 2000);
});
});
});
</script>
</body>
</html>