You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(a11y): add .sf-touch-target opt-in class for the WCAG 44px hit area
Scoping the automatic coarse-pointer floor to class-less controls (prev
commit) left classed controls — i.e. almost all real-world controls —
with no first-class way to request the 44px target beyond hand-rolling
min-sizes or the .sf-btn-only --sf-btn-min-height knob. Add the explicit
opt-in counterpart so the floor stays a safety net for bare markup while
the everyday mechanism is a class.
.sf-touch-target enforces min-block-size/min-inline-size:
var(--sf-touch-target) on both axes and centres a short label via
inline-flex (so it also works on inline elements like <a>). It lives in
core/accessibility.css alongside .sr-only / .skip-link / .sf-focus-shadow,
so it ships in every bundle, not just full. It is a single class
(specificity 0,1,0) with no !important, so a component rule can still opt a
specific control back out. Unlike the automatic floor it is not gated to a
coarse pointer — an explicit opt-in is predictable on every device.
- core/accessibility.css: add the .sf-touch-target helper + rationale
- tests/a11y-patterns.spec.js: enforce-on-classed-control and
overridable-without-!important guards
- docs/migration.md: document .sf-touch-target as the primary remedy
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GgL6mqSxe2ihjaUCxx78eR
Copy file name to clipboardExpand all lines: configurator/src/data/classes.generated.json
+10Lines changed: 10 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -3074,6 +3074,16 @@
3074
3074
"optional": false,
3075
3075
"layer": "slashed.themes"
3076
3076
},
3077
+
{
3078
+
"name": "sf-touch-target",
3079
+
"selector": ".sf-touch-target",
3080
+
"kind": "accessibility",
3081
+
"category": "Accessibility",
3082
+
"group": "",
3083
+
"description": ".sf-touch-target — the explicit opt-IN counterpart to the class-less floor above. Because the automatic floor deliberately never touches a control that carries a class, put this class on any control you own (a button with your own class, a link, a third-party widget you can add…",
Copy file name to clipboardExpand all lines: docs/api-index.json
+29-6Lines changed: 29 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -25,27 +25,27 @@
25
25
"optimal"
26
26
],
27
27
"counts": {
28
-
"total": 1053,
28
+
"total": 1054,
29
29
"by_type": {
30
-
"class": 312,
30
+
"class": 313,
31
31
"token": 741
32
32
},
33
33
"by_tier": {
34
34
"INTERNAL": 1,
35
-
"PUBLIC": 1003,
35
+
"PUBLIC": 1004,
36
36
"PUBLIC-ADVANCED": 49
37
37
},
38
38
"by_role": {
39
39
"consumption": 488,
40
40
"knob": 253
41
41
},
42
42
"tokens": 741,
43
-
"classes": 312,
44
-
"sf_classes": 289,
43
+
"classes": 313,
44
+
"sf_classes": 290,
45
45
"is_classes": 15,
46
46
"unprefixed_classes": 8,
47
47
"by_category": {
48
-
"Accessibility": 8,
48
+
"Accessibility": 9,
49
49
"Component tokens": 46,
50
50
"Components": 30,
51
51
"Core tokens": 610,
@@ -26314,6 +26314,29 @@
26314
26314
"optimal"
26315
26315
]
26316
26316
},
26317
+
{
26318
+
"name": "sf-touch-target",
26319
+
"type": "class",
26320
+
"tier": "PUBLIC",
26321
+
"selector": ".sf-touch-target",
26322
+
"prefix": "sf",
26323
+
"kind": "accessibility",
26324
+
"category": "Accessibility",
26325
+
"area": "accessibility",
26326
+
"group": "",
26327
+
"description": ".sf-touch-target — the explicit opt-IN counterpart to the class-less floor above. Because the automatic floor deliberately never touches a control that carries a class, put this class on any control you own (a button with your own class, a link, a third-party widget you can add…",
Copy file name to clipboardExpand all lines: docs/api-index.md
+5-4Lines changed: 5 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,11 +10,11 @@ and a short description. The machine-readable companion (with all columns) is
10
10
[registry.json](registry.json); for the tier contract see
11
11
[architecture.md](architecture.md).
12
12
13
-
**1053 elements** — 741 tokens, 312 classes.
13
+
**1054 elements** — 741 tokens, 313 classes.
14
14
15
15
| Tier | Count | Meaning |
16
16
|---|---|---|
17
-
| PUBLIC |1003| Everyday surface. SemVer-stable. |
17
+
| PUBLIC |1004| Everyday surface. SemVer-stable. |
18
18
| PUBLIC-ADVANCED | 49 | Same SemVer guarantee; niche/powerful. |
19
19
| INTERNAL | 1 | Implementation detail; may change without a major bump. |
20
20
@@ -781,9 +781,9 @@ and a short description. The machine-readable companion (with all columns) is
781
781
|`--sf-surface-bg-size`| PUBLIC | knob | surface |`cover`| background-size for the .sf-surface-bg image. Default: cover. |
782
782
|`--sf-surface-color`| PUBLIC | consumption | surface |`var(--sf-color-base)`| Input for the generic .sf-surface macro. Set any color (including palette shades); the macro derives background, auto-contrast foreground, and the contextual token set from it. |
783
783
784
-
## Classes (312)
784
+
## Classes (313)
785
785
786
-
### Accessibility (8)
786
+
### Accessibility (9)
787
787
788
788
| Class | Tier | Kind | Group | Description |
789
789
|---|---|---|---|---|
@@ -792,6 +792,7 @@ and a short description. The machine-readable companion (with all columns) is
792
792
|`.sf-clickable-parent__overlay`| PUBLIC | accessibility | — | The full-bleed overlay link inside an sf-clickable-parent. Stretches to cover the parent and uses pointer-events to let interactive children keep their own clicks. |
793
793
|`.sf-focus-parent`| PUBLIC | accessibility | — | Forwards focus-visible styling to this container when any descendant is keyboard-focused. Useful for custom controls that wrap a visually-hidden <input>. |
794
794
|`.sf-focus-shadow`| PUBLIC | accessibility | — | Applies the standard focus ring as a box-shadow to any element. Use on custom controls where the native :focus-visible ring doesn't render correctly. |
795
+
|`.sf-touch-target`| PUBLIC | accessibility | — | .sf-touch-target — the explicit opt-IN counterpart to the class-less floor above. Because the automatic floor deliberately never touches a control that carries a class, put this class on any control you own (a button with your own class, a link, a third-party widget you can add… |
795
796
|`.skip-link`| PUBLIC | accessibility | — | Accessible skip-navigation link. Hidden until focused; jumps keyboard users past repeated navigation blocks. Place as the very first element in <body>. |
796
797
|`.sr-only`| PUBLIC | accessibility | — | Visually hides content while keeping it accessible to screen readers. Use for labels, descriptions, and off-screen text that assistive technology needs. |
797
798
|`.sr-only-focusable`| PUBLIC | accessibility | — | Extends sr-only — also reveals the element when it receives keyboard focus. Typical use: skip links and visually-hidden focus targets. |
0 commit comments