-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
186 lines (169 loc) · 10.6 KB
/
index.html
File metadata and controls
186 lines (169 loc) · 10.6 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
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tooltip - Resonance Labs</title>
<link rel="stylesheet" href="/resonance-labs/assets/style/global.css" />
<link rel="stylesheet" href="tooltip.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>Tooltip</h1>
<p class="component-tagline">A tooltip is a small popup providing brief contextual information when a user hovers over or focuses on a trigger element, and it must be dismissable with the Escape key.</p>
</div>
<div class="section">
<h2>Demo</h2>
<p>Hover your pointer over the trigger element to reveal the tooltip. Then tab to the trigger with the keyboard to confirm the tooltip also appears on focus. While the tooltip is visible, press <strong>Escape</strong> to dismiss it. Notice that the tooltip content is read by a screen reader when the trigger receives focus.</p>
<div class="mount"></div>
</div>
<div class="section">
<h2>What to Observe</h2>
<ul>
<li>The tooltip appears on both hover and keyboard focus — not only on hover, which would make it inaccessible to keyboard users.</li>
<li>Pressing Escape while the tooltip is visible dismisses it and returns focus to the trigger without disrupting the user's place in the page.</li>
<li>A screen reader announces the tooltip content when focus lands on the trigger, without requiring the user to navigate to the tooltip separately.</li>
<li>The tooltip content is purely informational — it contains no links, buttons, or other interactive elements.</li>
<li>The tooltip does not disappear automatically after a short timer; it remains visible as long as the trigger is hovered or focused.</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>Trigger element:</strong> The focusable element (button, icon, or link) that a user hovers over or focuses on to reveal the tooltip; it carries an <code>aria-describedby</code> attribute pointing to the tooltip content.</li>
<li><strong>Tooltip container:</strong> The popup element with <code>role="tooltip"</code> and a matching <code>id</code> referenced by the trigger's <code>aria-describedby</code>.</li>
<li><strong>Tooltip text:</strong> The brief descriptive message inside the container; it supplements context but does not replace the trigger's own accessible name.</li>
<li><strong>Caret or pointer:</strong> An optional visual arrow connecting the tooltip bubble to its trigger, helping users understand which element the tooltip describes.</li>
</ol>
</div>
<div class="section">
<h2>Accessibility Behavior</h2>
<ul>
<li>The tooltip must appear on both pointer hover and keyboard focus — hover-only tooltips are inaccessible to keyboard users.</li>
<li>The tooltip element must have <code>role="tooltip"</code>, and the trigger must reference it through <code>aria-describedby</code> so screen readers read the content as supplemental description.</li>
<li>Pressing Escape while the tooltip is visible must dismiss it without moving focus away from the trigger.</li>
<li>The tooltip must not contain interactive elements such as links or buttons — it is a read-only description, not a dialog.</li>
<li>The tooltip must remain visible long enough for users to read it — it must not auto-dismiss after a brief timeout.</li>
<li>Tooltip text must supplement the trigger's label and never serve as the trigger's only accessible name.</li>
</ul>
</div>
<div class="section">
<h2>Common Mistakes</h2>
<ul>
<li>Triggering the tooltip only on hover, making it completely unreachable for keyboard users and touch device users.</li>
<li>Placing interactive content such as links inside the tooltip, which users cannot reach because tooltips are not meant to receive focus.</li>
<li>Using the tooltip as the only label for a control — for example, an icon button with no text that relies entirely on its tooltip for meaning.</li>
<li>Auto-dismissing the tooltip after a few seconds, which prevents users who read slowly from consuming the content before it disappears.</li>
<li>Omitting <code>role="tooltip"</code> or the <code>aria-describedby</code> link, so screen readers never read the tooltip content to the user.</li>
</ul>
</div>
<div class="section">
<h2>Why This Matters</h2>
<p>Tooltips are frequently used on icon-only buttons, truncated text, and form field hints — exactly the places where supplemental context is most critical. When a tooltip only works on hover, keyboard users and touch-screen users get no access to that context at all. Worse, when developers use tooltips as the sole label for an unlabeled icon button, the button becomes completely meaningless to any user who cannot trigger the hover state. Proper tooltip implementation is one of the simplest ways to ensure all users have access to the same contextual information.</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("./tooltip.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*/g, "").replace(/<script type="application\/json"[\s\S]*?<\/script>\n*/g, "").trim();
var codeHtml = document.getElementById("code-html");
codeHtml.textContent = rawHtml;
Prism.highlightElement(codeHtml);
// Load component JS
var s = document.createElement("script");
s.src = "./tooltip.js";
document.body.appendChild(s);
});
// Fetch CSS
fetch("./tooltip.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("./tooltip.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>