@codenhub/styles 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +18 -16
- package/README.es.md +61 -0
- package/README.md +27 -22
- package/README.pt-BR.md +61 -0
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +2 -2
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -1
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/dist/tw/aesthetics/chunky-tile.css +120 -62
- package/dist/tw/aesthetics/cyber.css +102 -40
- package/dist/tw/aesthetics/glass.css +371 -19
- package/dist/tw/aesthetics/index.css +2 -1
- package/dist/tw/aesthetics/neobrutalism.css +121 -33
- package/dist/tw/aesthetics/pixel.css +111 -16
- package/dist/tw/aesthetics/sketch.css +100 -28
- package/dist/tw/box.css +69 -28
- package/dist/tw/components/button.css +35 -14
- package/dist/tw/components/feedback.css +61 -58
- package/dist/tw/components/form.css +255 -142
- package/dist/tw/components/index.css +4 -9
- package/dist/tw/components/surface.css +80 -68
- package/dist/tw/components/tooltip.css +75 -41
- package/dist/tw/elevation.css +14 -22
- package/dist/tw/index.css +15 -19
- package/dist/tw/intent.css +35 -27
- package/dist/tw/native.css +22 -12
- package/dist/tw/palette.css +14 -11
- package/dist/tw/presentation.css +16 -30
- package/dist/tw/reset.css +36 -43
- package/dist/tw/surface.css +11 -12
- package/dist/tw/theme.css +87 -103
- package/dist/tw/utilities/content.css +311 -200
- package/dist/tw/utilities/layout.css +41 -37
- package/docs/accessibility.md +104 -58
- package/docs/changelog/0.1.1.md +1 -0
- package/docs/changelog/0.2.0.md +1 -0
- package/docs/changelog/0.3.0.md +1 -0
- package/docs/changelog/0.4.0.md +1 -0
- package/docs/changelog/0.5.0.md +8 -3
- package/docs/changelog/0.6.0.md +53 -0
- package/docs/changelog/0.7.0.md +50 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +188 -46
- package/docs/es/accessibility.md +150 -0
- package/docs/es/concepts.md +212 -0
- package/docs/es/index.md +104 -0
- package/docs/es/integrating/astro.md +35 -0
- package/docs/es/integrating/index.md +47 -0
- package/docs/es/integrating/nextjs.md +67 -0
- package/docs/es/integrating/svelte.md +45 -0
- package/docs/es/integrating/tailwind.md +78 -0
- package/docs/es/integrating/vue.md +31 -0
- package/docs/es/integrating/without-a-bundler.md +115 -0
- package/docs/es/setup.md +180 -0
- package/docs/es/usage/aesthetics.md +276 -0
- package/docs/es/usage/buttons.md +131 -0
- package/docs/es/usage/composing.md +164 -0
- package/docs/es/usage/content-and-layout.md +215 -0
- package/docs/es/usage/customizing.md +298 -0
- package/docs/es/usage/feedback.md +153 -0
- package/docs/es/usage/forms.md +231 -0
- package/docs/es/usage/index.md +29 -0
- package/docs/es/usage/solo.md +84 -0
- package/docs/es/usage/theming.md +296 -0
- package/docs/es/usage/tooltips.md +127 -0
- package/docs/index.md +89 -21
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +18 -13
- package/docs/integrating/nextjs.md +4 -5
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +29 -8
- package/docs/integrating/vue.md +3 -4
- package/docs/integrating/without-a-bundler.md +114 -0
- package/docs/pt-BR/accessibility.md +150 -0
- package/docs/pt-BR/concepts.md +212 -0
- package/docs/pt-BR/index.md +104 -0
- package/docs/pt-BR/integrating/astro.md +35 -0
- package/docs/pt-BR/integrating/index.md +47 -0
- package/docs/pt-BR/integrating/nextjs.md +67 -0
- package/docs/pt-BR/integrating/svelte.md +45 -0
- package/docs/pt-BR/integrating/tailwind.md +78 -0
- package/docs/pt-BR/integrating/vue.md +31 -0
- package/docs/pt-BR/integrating/without-a-bundler.md +115 -0
- package/docs/pt-BR/setup.md +180 -0
- package/docs/pt-BR/usage/aesthetics.md +276 -0
- package/docs/pt-BR/usage/buttons.md +131 -0
- package/docs/pt-BR/usage/composing.md +164 -0
- package/docs/pt-BR/usage/content-and-layout.md +215 -0
- package/docs/pt-BR/usage/customizing.md +298 -0
- package/docs/pt-BR/usage/feedback.md +153 -0
- package/docs/pt-BR/usage/forms.md +231 -0
- package/docs/pt-BR/usage/index.md +29 -0
- package/docs/pt-BR/usage/solo.md +84 -0
- package/docs/pt-BR/usage/theming.md +296 -0
- package/docs/pt-BR/usage/tooltips.md +127 -0
- package/docs/setup.md +134 -91
- package/docs/usage/aesthetics.md +102 -65
- package/docs/usage/buttons.md +108 -40
- package/docs/usage/composing.md +105 -92
- package/docs/usage/content-and-layout.md +159 -127
- package/docs/usage/customizing.md +112 -43
- package/docs/usage/feedback.md +135 -70
- package/docs/usage/forms.md +184 -99
- package/docs/usage/index.md +18 -14
- package/docs/usage/solo.md +83 -0
- package/docs/usage/theming.md +260 -119
- package/docs/usage/tooltips.md +103 -42
- package/llms-full.txt +2465 -1272
- package/llms.txt +25 -17
- package/package.json +28 -35
- package/dist/tw/components/loader.css +0 -117
package/docs/usage/tooltips.md
CHANGED
|
@@ -1,65 +1,126 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Tooltips
|
|
3
|
-
description:
|
|
4
|
-
order:
|
|
3
|
+
description: Field help that opens on hover and focus, how to connect it for screen readers and Escape, and where a tooltip gets cut off.
|
|
4
|
+
order: 4
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Tooltips
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
| -------------------------------------- | ------------------------------------------------------------------------ |
|
|
11
|
-
| `.tooltip` | Wrapper around a trigger and a bubble. Paints nothing itself. |
|
|
12
|
-
| `.tooltip-bubble` | The message. A real element, styled like any other surface. |
|
|
13
|
-
| `.tooltip-icon` | Circular icon-style trigger, for a message with nothing else to hang on. |
|
|
14
|
-
| `[data-tooltip-position="top"]` | Positions the bubble above the trigger, on `.tooltip`. |
|
|
15
|
-
| `[data-tooltip-position="bottom"]` | Positions the bubble below the trigger, on `.tooltip`. |
|
|
16
|
-
| `[data-tooltip-position="left"]` | Positions the bubble left of the trigger, on `.tooltip`. |
|
|
17
|
-
| `[data-tooltip-position="right"]` | Positions the bubble right of the trigger, on `.tooltip`. |
|
|
18
|
-
| No `data-tooltip-position` | Defaults to top placement. |
|
|
19
|
-
| `[data-state="open"]` | Shows the bubble without hover, on `.tooltip`. |
|
|
20
|
-
| `.tooltip-bubble.raised` / `.floating` | Adds one or two units of depth. The bubble is flat by default. |
|
|
9
|
+
The "Public profile" switch on the settings screen deserves a short explanation: what becomes visible when it is on. This page adds a help button beside it that shows a tooltip on hover and on keyboard focus. The CSS shows and hides the message and draws it; you connect it to its trigger for screen readers, add the Escape key, and check that nothing around it cuts it off.
|
|
21
10
|
|
|
22
|
-
|
|
11
|
+
## A help tooltip
|
|
23
12
|
|
|
24
|
-
|
|
13
|
+
```html
|
|
14
|
+
<div class="cluster tight">
|
|
15
|
+
<label class="cluster tight">
|
|
16
|
+
<input class="switch primary" type="checkbox" role="switch" name="public-profile" />
|
|
17
|
+
Public profile
|
|
18
|
+
</label>
|
|
19
|
+
<span class="tooltip">
|
|
20
|
+
<button class="tooltip-icon" type="button" aria-label="About public profiles" aria-describedby="public-profile-help">?</button>
|
|
21
|
+
<span class="tooltip-bubble" role="tooltip" id="public-profile-help">Anyone with the link can see your name, photo, and public projects.</span>
|
|
22
|
+
</span>
|
|
23
|
+
</div>
|
|
24
|
+
```
|
|
25
25
|
|
|
26
|
-
The
|
|
26
|
+
The three parts:
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
- `.tooltip` wraps the trigger and the message. It positions the message and paints nothing itself.
|
|
29
|
+
- `.tooltip-bubble` is the message. It is a real element, so it can have an `id` that the trigger points to.
|
|
30
|
+
- `.tooltip-icon` is a small round trigger, for a message with nothing else to attach to. Any focusable element can be the trigger instead: wrap an existing `.btn` in `.tooltip` and it keeps its own look.
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
Connect them yourself: an `id` on the bubble, `aria-describedby` on the trigger pointing to that `id`, and `role="tooltip"` on the bubble. A screen reader then reads the message as the trigger's description. The CSS cannot make this connection, and without it the message is visual only.
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
<span class="tooltip">
|
|
34
|
-
<button aria-describedby="status-bubble">Status</button>
|
|
35
|
-
<span class="tooltip-bubble" role="tooltip" id="status-bubble">Saved 2 minutes ago</span>
|
|
36
|
-
</span>
|
|
34
|
+
The trigger must be focusable, such as a `<button>`, so keyboard users can reach the message. The bubble opens when anything inside `.tooltip` has focus, so it also opens after a mouse click on the trigger.
|
|
37
35
|
|
|
36
|
+
## Placement
|
|
37
|
+
|
|
38
|
+
The bubble opens above its trigger, horizontally centered, with a 0.5rem gap. Set `data-tooltip-position` on `.tooltip` to choose another side:
|
|
39
|
+
|
|
40
|
+
```html
|
|
38
41
|
<span class="tooltip" data-tooltip-position="bottom">
|
|
39
|
-
<button aria-describedby="
|
|
40
|
-
<span class="tooltip-bubble" role="tooltip" id="
|
|
42
|
+
<button class="btn ghost sm" type="button" aria-describedby="renewal-help">Renews 12 March 2027</button>
|
|
43
|
+
<span class="tooltip-bubble" role="tooltip" id="renewal-help">Your card is charged on this date.</span>
|
|
41
44
|
</span>
|
|
45
|
+
```
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
| `data-tooltip-position` | Bubble |
|
|
48
|
+
| ----------------------- | ------------------------------------------------- |
|
|
49
|
+
| _none_ or `"top"` | Above the trigger, centered. |
|
|
50
|
+
| `"bottom"` | Below the trigger, centered. |
|
|
51
|
+
| `"left"` | To the left of the trigger, centered vertically. |
|
|
52
|
+
| `"right"` | To the right of the trigger, centered vertically. |
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
<span aria-describedby="pinned-bubble">Pinned</span>
|
|
50
|
-
<span class="tooltip-bubble" role="tooltip" id="pinned-bubble">Always visible, no hover needed</span>
|
|
51
|
-
</span>
|
|
54
|
+
A bubble is as wide as its text, up to 18rem, and then wraps.
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
### Where a tooltip gets cut off
|
|
57
|
+
|
|
58
|
+
The bubble is positioned with CSS only, on the side you chose. Nothing measures the page: it does not move to stay inside the window, flip to the other side when there is no room, or move to the top layer of the page. That has three consequences:
|
|
59
|
+
|
|
60
|
+
- **A scrolling or clipping container cuts it off.** An ancestor with `overflow: hidden`, `auto`, or `scroll` clips the bubble at its edge. The API keys table on the settings screen sits in a `.table-wrap`, which scrolls, so a top tooltip on the first row is cut off at the top of the wrapper. Raising `z-index` does not help: it changes what the bubble is painted above, not whether the container clips it.
|
|
61
|
+
- **The window edge cuts it off.** A top tooltip on the first line of a page, or a right tooltip near the right edge, extends off screen.
|
|
62
|
+
- **Left and right are physical sides.** In a right-to-left page, `"left"` still means the left side of the screen.
|
|
63
|
+
|
|
64
|
+
What to do:
|
|
65
|
+
|
|
66
|
+
- Choose a side with room: on a table's first row, use `data-tooltip-position="bottom"`.
|
|
67
|
+
- Move the tooltip's trigger out of the clipping container, or remove the `overflow` from a container that does not need it.
|
|
68
|
+
- If the trigger's position cannot be known in advance, such as in a scrolling list or a resizable panel, use a positioning library or your framework's popover component, which can measure and flip. You can still give its message element the `.tooltip-bubble` classes for the look, but the showing, hiding, and positioning described on this page then come from that library, not from `.tooltip`.
|
|
69
|
+
|
|
70
|
+
## Hover, linger, and Escape
|
|
71
|
+
|
|
72
|
+
WCAG 1.4.13 asks three things of content that appears on hover or focus. The package handles two:
|
|
73
|
+
|
|
74
|
+
- **Hoverable.** When the pointer leaves the trigger, the bubble stays for `--tooltip-linger` (300ms) and then fades, so the pointer can cross the gap onto it. It stays open while the pointer is over it. A closed bubble is `visibility: hidden`, so it never catches the pointer.
|
|
75
|
+
- **Persistent.** It stays open until the pointer and focus leave.
|
|
76
|
+
- **Dismissible.** The user must be able to close it without moving the pointer or focus, usually with Escape. CSS cannot listen for a key, so this part is yours.
|
|
77
|
+
|
|
78
|
+
To change the linger time, set `--tooltip-linger` on the `.tooltip` element, for example `style="--tooltip-linger: 500ms"`. The wrapper declares its own default, so a value set on a parent of `.tooltip` has no effect. Keep it long enough for the pointer to reach the bubble. It is one of six [public component variables](./customizing.md#component-variables).
|
|
79
|
+
|
|
80
|
+
For Escape, write `data-state="closed"` on `.tooltip`: it hides the bubble even while it is hovered or focused. Remove the attribute only when both the pointer and focus have left the tooltip, so the next hover or focus opens it again. Removing it earlier, while the trigger still has focus, makes the message reappear without the user doing anything.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
for (const tooltip of document.querySelectorAll(".tooltip")) {
|
|
84
|
+
let pointerInside = tooltip.matches(":hover");
|
|
85
|
+
|
|
86
|
+
tooltip.addEventListener("pointerenter", () => {
|
|
87
|
+
pointerInside = true;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
tooltip.addEventListener("pointerleave", () => {
|
|
91
|
+
pointerInside = false;
|
|
92
|
+
if (!tooltip.contains(document.activeElement)) tooltip.removeAttribute("data-state");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
tooltip.addEventListener("focusout", (event) => {
|
|
96
|
+
const focusStaysInside = tooltip.contains(event.relatedTarget);
|
|
97
|
+
if (!focusStaysInside && !pointerInside) tooltip.removeAttribute("data-state");
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
document.addEventListener("keydown", (event) => {
|
|
102
|
+
if (event.key !== "Escape") return;
|
|
103
|
+
for (const tooltip of document.querySelectorAll(".tooltip:hover, .tooltip:focus-within")) {
|
|
104
|
+
tooltip.dataset.state = "closed";
|
|
105
|
+
}
|
|
106
|
+
});
|
|
57
107
|
```
|
|
58
108
|
|
|
59
|
-
|
|
109
|
+
`data-state="open"` does the opposite: it shows the bubble with no hover or focus, for a message that should stay visible, or for a test or a screenshot.
|
|
110
|
+
|
|
111
|
+
## How the bubble looks
|
|
112
|
+
|
|
113
|
+
With no intent class, the bubble uses `--color-tooltip`, a background chosen per theme: near-white on a light page, mid gray on a dark one, with `--color-tooltip-contrast` as its text color. Near-white measures only 1.04:1 against a light page, so the bubble also draws a thin border, and a container's `.edgeless` cannot remove it. `.edgeless` on the bubble itself still can. The background stays opaque under any presentation, so the bubble stays readable over whatever it covers.
|
|
114
|
+
|
|
115
|
+
An intent class fills the bubble with that intent's color and switches the text to the matching contrast color:
|
|
116
|
+
|
|
117
|
+
- `.tooltip-bubble.primary` has a near-black background with near-white text on a light page, and a near-white background with near-black text on a dark one.
|
|
118
|
+
- `.tooltip-bubble.destructive` has a red background with light text in both themes.
|
|
119
|
+
|
|
120
|
+
Put intent, presentation, aesthetic, and elevation classes on `.tooltip-bubble`, the element that is painted, not on `.tooltip`. The bubble is flat by default, even under an aesthetic that draws depth; add `.raised` or `.floating` to the bubble to lift it. An aesthetic in scope shapes the bubble like any other component; under `.glass` it is frosted like a card. `.tooltip-icon` takes the aesthetic's corner: square under `.neobrutalism` and `.pixel`, a diamond under `.cyber`.
|
|
60
121
|
|
|
61
|
-
|
|
122
|
+
The bubble appears without scaling up when the user asks for reduced motion.
|
|
62
123
|
|
|
63
|
-
|
|
124
|
+
## Next
|
|
64
125
|
|
|
65
|
-
|
|
126
|
+
The settings screen is complete in its default look. [Theming](./theming.md) gives it a dark mode and your brand colors.
|