-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
190 lines (173 loc) · 10.4 KB
/
index.html
File metadata and controls
190 lines (173 loc) · 10.4 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
189
190
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Card - Resonance Labs</title>
<link rel="stylesheet" href="/resonance-labs/assets/style/global.css" />
<link rel="stylesheet" href="card.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>Card</h1>
<p class="component-tagline">A contained surface that groups related content — such as a title, description, and call to action — into a single clickable unit without nesting multiple interactive elements.</p>
</div>
<div class="section">
<h2>Demo</h2>
<p>Tab to the card and activate it with Enter. Observe that a single link is reachable per card, that the link's accessible name reflects the card's content, and that no other interactive elements inside the card interrupt the tab order unexpectedly.</p>
<div class="mount"></div>
</div>
<div class="section">
<h2>What to Observe</h2>
<ul>
<li>Exactly one focusable element per card is reachable by keyboard — the primary link</li>
<li>The link's accessible name is descriptive enough to identify the card's destination without surrounding context</li>
<li>The card image is either described through the link text or hidden from assistive technology if it is purely decorative</li>
<li>The clickable surface area is large without requiring multiple redundant links to the same destination</li>
<li>Visual hover and focus states are distinct and clearly communicate the card's interactive nature</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>Card Container</strong> — the wrapping element that visually groups the card's content and provides position context for the full-surface link overlay</li>
<li><strong>Card Image</strong> — an optional visual element at the top of the card; decorative images are hidden from assistive technology, while meaningful images carry descriptive alternative text</li>
<li><strong>Card Title</strong> — a heading or prominently styled text that names the card's subject and provides the primary accessible name for the card's link</li>
<li><strong>Card Description</strong> — supporting text that gives additional context about the card's content or destination</li>
<li><strong>Primary Link</strong> — the anchor element whose stretched or overlaid click target covers the full card surface, providing a large interaction area without nesting multiple links</li>
</ol>
</div>
<div class="section">
<h2>Accessibility Behavior</h2>
<ul>
<li>Ensure the card has exactly one focusable element reachable by keyboard — typically the primary link — so keyboard users do not encounter multiple redundant paths to the same destination</li>
<li>Give the primary link an accessible name that is descriptive on its own, without requiring the surrounding card content to provide context</li>
<li>Use a CSS overlay or stretching technique to expand the link's click target to the full card surface, rather than wrapping all card content inside an anchor element</li>
<li>Mark decorative card images with empty alternative text so assistive technology does not announce them as part of the card's content</li>
<li>Ensure the card's focus indicator is visible and clearly indicates that the card surface is interactive</li>
</ul>
</div>
<div class="section">
<h2>Common Mistakes</h2>
<ul>
<li>Wrapping the entire card in an anchor element, which causes screen readers to announce all card content as part of the link text and produces an overwhelming announcement</li>
<li>Including multiple links inside a card pointing to the same destination, creating redundant tab stops that slow down keyboard navigation</li>
<li>Using a generic link label such as "Read more" or "Learn more" that provides no indication of the destination without the surrounding visual context</li>
<li>Omitting alternative text on meaningful card images, leaving screen reader users without the visual information the image conveys</li>
<li>Making the card clickable via JavaScript on the container div without providing a keyboard-operable link inside it</li>
</ul>
</div>
<div class="section">
<h2>Why This Matters</h2>
<p>Cards are ubiquitous in modern interfaces — article listings, product grids, resource libraries — yet they are routinely implemented in ways that create barriers. Wrapping an entire card in an anchor causes screen readers to read every line of content as one long link. Multiple redundant links force keyboard users to tab through unnecessary stops. Vague link text like "Read more" is meaningless when encountered in a links list. The card pattern requires deliberate decisions about link structure, accessible names, and image handling to work equally well for all users.</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("./card.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 = "./card.js";
document.body.appendChild(s);
});
// Fetch CSS
fetch("./card.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("./card.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>