diff --git a/.changeset/touch-select-papercuts.md b/.changeset/touch-select-papercuts.md
new file mode 100644
index 0000000..4c6732d
--- /dev/null
+++ b/.changeset/touch-select-papercuts.md
@@ -0,0 +1,14 @@
+---
+"@kernelui-lib/styles": patch
+"@kernelui-lib/react": patch
+"@kernelui-lib/elements": patch
+---
+
+Stop tap flash and accidental text selection on clickable controls.
+
+The reset now includes `label` (tapping a checkbox label highlighted the
+label, not the input) plus the widget roles, kills the iOS long-press
+callout on chrome, and sets `user-select: none` on buttons, summaries, and
+labels. React and Web Components pair `-webkit-user-select` everywhere
+selection is suppressed, including nav, breadcrumbs, and chips. Links stay
+selectable so copying their text still works.
diff --git a/AGENTS.md b/AGENTS.md
index ea32f7a..9fc9dc2 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -131,7 +131,13 @@ new component done, grep both `packages/react/src/index.ts` and
was for, and a drag from a control selects text across the page. Pair it
with `-webkit-user-select: none` for Safari. Same rule for gutters that
aren't content: line numbers and diff markers are `user-select: none` so
- a copy contains code, not decoration.
+ a copy contains code, not decoration. Tap flash and the iOS long-press
+ callout are a reset concern, not a per-component one: `packages/styles`'
+ reset kills `-webkit-tap-highlight-color` and sets `touch-action:
+ manipulation` on `a`/`button`/`input`/`label`/`summary` and the widget
+ roles, and `-webkit-touch-callout: none` on the clickable-chrome subset
+ (not links — long-press to open in a new tab stays). Omitting `label`
+ from that list is how a checkbox tap still flashes grey on iOS.
- **Motion baseline** (tokens in `packages/styles/src/tokens.css`, craft
bar from [transitions.dev](https://transitions.dev/) + Emil): enter with
`--kernel-ease-overlay` / `--kernel-ease-out`, never `ease-in` on
diff --git a/apps/docs/src/styles/global.css b/apps/docs/src/styles/global.css
index 1fd82e1..388e7f4 100644
--- a/apps/docs/src/styles/global.css
+++ b/apps/docs/src/styles/global.css
@@ -209,6 +209,9 @@ h3 {
background: none;
color: var(--kernel-color-text-muted);
cursor: default;
+ -webkit-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out),
color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -280,6 +283,7 @@ p.docs-sidebar-eyebrow:first-child {
gap: var(--kernel-space-2);
cursor: pointer;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
}
@@ -364,6 +368,8 @@ p.docs-sidebar-eyebrow:first-child {
border-inline-start: var(--kernel-border-width) solid transparent;
padding-inline-start: var(--kernel-space-3);
margin-inline-start: calc(var(--kernel-space-3) * -1 - var(--kernel-border-width));
+ -webkit-user-select: none;
+ user-select: none;
transition: color var(--kernel-duration-fast) var(--kernel-ease-out),
border-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -445,6 +451,8 @@ dialog.mobile-nav-panel[data-side="left"] {
font-size: var(--kernel-font-size-sm);
text-decoration: none;
white-space: nowrap;
+ -webkit-user-select: none;
+ user-select: none;
}
.site-header-registry-link svg {
@@ -663,6 +671,8 @@ dialog.mobile-nav-panel[data-side="left"] {
minimum costs no layout. */
min-block-size: 24px;
color: var(--kernel-color-text);
+ -webkit-user-select: none;
+ user-select: none;
}
.site-header-logo-icon {
@@ -1373,8 +1383,8 @@ dialog.mobile-nav-panel[data-side="left"] {
background: transparent;
color: var(--kernel-color-text);
cursor: grab;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
inline-size: 5.5rem;
flex: 0 0 auto;
translate: var(--desktop-nudge-x, 0) var(--desktop-nudge-y, 0);
@@ -2213,6 +2223,7 @@ dialog.mobile-nav-panel[data-side="left"] {
font-weight: 500;
cursor: default;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -2260,6 +2271,7 @@ dialog.mobile-nav-panel[data-side="left"] {
resizing, matching the library Accordion's own rule. */
.usage-accordion[data-state="opening"] .usage-accordion-content,
.usage-accordion[data-state="closing"] .usage-accordion-content {
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/Accordion/Accordion.css b/packages/elements/src/components/Accordion/Accordion.css
index 788bd68..c487c9f 100644
--- a/packages/elements/src/components/Accordion/Accordion.css
+++ b/packages/elements/src/components/Accordion/Accordion.css
@@ -27,6 +27,7 @@ kernel-accordion-item:last-of-type .kernel-Accordion-item {
font-weight: 500;
cursor: default;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -85,6 +86,7 @@ kernel-accordion-item:last-of-type .kernel-Accordion-item[open] .kernel-Accordio
.kernel-Accordion-item[data-state="opening"] .kernel-Accordion-content,
.kernel-Accordion-item[data-state="closing"] .kernel-Accordion-content {
overflow: clip;
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/Breadcrumbs/Breadcrumbs.css b/packages/elements/src/components/Breadcrumbs/Breadcrumbs.css
index fdb758e..77dde50 100644
--- a/packages/elements/src/components/Breadcrumbs/Breadcrumbs.css
+++ b/packages/elements/src/components/Breadcrumbs/Breadcrumbs.css
@@ -46,6 +46,8 @@ kernel-breadcrumb-item {
color: var(--kernel-color-text-muted);
text-decoration: none;
border-radius: var(--kernel-radius-sm);
+ -webkit-user-select: none;
+ user-select: none;
}
/* Guarded, matching the React package: on a touch device :hover latches
diff --git a/packages/elements/src/components/Button/Button.css b/packages/elements/src/components/Button/Button.css
index 4a5652b..3a91643 100644
--- a/packages/elements/src/components/Button/Button.css
+++ b/packages/elements/src/components/Button/Button.css
@@ -11,7 +11,10 @@
white-space: nowrap;
text-decoration: none;
cursor: default;
+ -webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
border-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/Carousel/Carousel.css b/packages/elements/src/components/Carousel/Carousel.css
index b799357..8b312bf 100644
--- a/packages/elements/src/components/Carousel/Carousel.css
+++ b/packages/elements/src/components/Carousel/Carousel.css
@@ -49,6 +49,7 @@ kernel-carousel-slide {
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -96,6 +97,7 @@ kernel-carousel-slide {
border-radius: var(--kernel-radius-full);
background-color: var(--kernel-color-border-interactive);
cursor: default;
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/elements/src/components/Checkbox/Checkbox.css b/packages/elements/src/components/Checkbox/Checkbox.css
index 1339d8b..cf84f58 100644
--- a/packages/elements/src/components/Checkbox/Checkbox.css
+++ b/packages/elements/src/components/Checkbox/Checkbox.css
@@ -6,6 +6,8 @@
cursor: pointer;
-webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
font-family: var(--kernel-font-sans);
font-size: var(--kernel-font-size-base);
color: var(--kernel-color-text);
diff --git a/packages/elements/src/components/CodeBlock/CodeBlock.css b/packages/elements/src/components/CodeBlock/CodeBlock.css
index 7def51b..e199af9 100644
--- a/packages/elements/src/components/CodeBlock/CodeBlock.css
+++ b/packages/elements/src/components/CodeBlock/CodeBlock.css
@@ -191,8 +191,8 @@ kernel-code-block {
color: var(--kernel-color-text-muted);
font-variant-numeric: tabular-nums;
text-align: end;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
}
.kernel-CodeBlock-lineText {
diff --git a/packages/elements/src/components/Combobox/Combobox.css b/packages/elements/src/components/Combobox/Combobox.css
index 9ccb78a..ff478f0 100644
--- a/packages/elements/src/components/Combobox/Combobox.css
+++ b/packages/elements/src/components/Combobox/Combobox.css
@@ -93,6 +93,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/CommandPalette/CommandPalette.css b/packages/elements/src/components/CommandPalette/CommandPalette.css
index f8f32d1..e79bf04 100644
--- a/packages/elements/src/components/CommandPalette/CommandPalette.css
+++ b/packages/elements/src/components/CommandPalette/CommandPalette.css
@@ -155,6 +155,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/DataTable/DataTable.css b/packages/elements/src/components/DataTable/DataTable.css
index 82df5a9..341e2f4 100644
--- a/packages/elements/src/components/DataTable/DataTable.css
+++ b/packages/elements/src/components/DataTable/DataTable.css
@@ -28,6 +28,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/DatePicker/DatePicker.css b/packages/elements/src/components/DatePicker/DatePicker.css
index 58100bb..6073800 100644
--- a/packages/elements/src/components/DatePicker/DatePicker.css
+++ b/packages/elements/src/components/DatePicker/DatePicker.css
@@ -36,6 +36,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
@@ -96,6 +97,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/DateRangePicker/DateRangePicker.css b/packages/elements/src/components/DateRangePicker/DateRangePicker.css
index 2421da8..e2cad84 100644
--- a/packages/elements/src/components/DateRangePicker/DateRangePicker.css
+++ b/packages/elements/src/components/DateRangePicker/DateRangePicker.css
@@ -36,6 +36,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
@@ -100,6 +101,7 @@
cursor: pointer;
/* Also matters here beyond the usual convention: hovering across cells
while previewing/selecting a range must not drag-select day text. */
+ -webkit-user-select: none;
user-select: none;
transition: scale var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/elements/src/components/DropdownMenu/DropdownMenu.css b/packages/elements/src/components/DropdownMenu/DropdownMenu.css
index 694320a..d3c8e50 100644
--- a/packages/elements/src/components/DropdownMenu/DropdownMenu.css
+++ b/packages/elements/src/components/DropdownMenu/DropdownMenu.css
@@ -81,6 +81,7 @@ kernel-menu-separator {
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/FileDiff/FileDiff.css b/packages/elements/src/components/FileDiff/FileDiff.css
index df95a4d..b872a9a 100644
--- a/packages/elements/src/components/FileDiff/FileDiff.css
+++ b/packages/elements/src/components/FileDiff/FileDiff.css
@@ -126,8 +126,8 @@ kernel-file-diff {
text-align: end;
vertical-align: top;
white-space: nowrap;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
}
/* The +/− marker is real text, not a colour. Colour alone doesn't say whether
@@ -137,8 +137,8 @@ kernel-file-diff {
padding-inline-start: var(--kernel-space-2);
vertical-align: top;
white-space: pre;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
}
.kernel-FileDiff-row[data-kind="add"] .kernel-FileDiff-marker {
diff --git a/packages/elements/src/components/FileUpload/FileUpload.css b/packages/elements/src/components/FileUpload/FileUpload.css
index 52903b6..e44a9c2 100644
--- a/packages/elements/src/components/FileUpload/FileUpload.css
+++ b/packages/elements/src/components/FileUpload/FileUpload.css
@@ -44,6 +44,7 @@
text-align: center;
cursor: pointer;
overflow: hidden;
+ -webkit-user-select: none;
user-select: none;
transition:
border-color var(--kernel-duration-enter) var(--kernel-ease-overlay),
@@ -236,6 +237,7 @@
/* A drag gesture that starts on/near a file row shouldn't fight the
browser's own text-selection heuristics — nothing in the row is
meant to be selected as text. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/Label/Label.css b/packages/elements/src/components/Label/Label.css
index bc9143d..c7d4f52 100644
--- a/packages/elements/src/components/Label/Label.css
+++ b/packages/elements/src/components/Label/Label.css
@@ -4,6 +4,8 @@
font-size: var(--kernel-font-size-sm);
font-weight: 500;
color: var(--kernel-color-text);
+ -webkit-user-select: none;
+ user-select: none;
}
.kernel-Label-required {
diff --git a/packages/elements/src/components/Nav/Nav.css b/packages/elements/src/components/Nav/Nav.css
index 5312d80..b329f1c 100644
--- a/packages/elements/src/components/Nav/Nav.css
+++ b/packages/elements/src/components/Nav/Nav.css
@@ -36,6 +36,8 @@ kernel-nav-link {
color: var(--kernel-color-text-muted);
text-decoration: none;
font-size: var(--kernel-font-size-sm);
+ -webkit-user-select: none;
+ user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
color var(--kernel-duration-fast) var(--kernel-ease-out);
diff --git a/packages/elements/src/components/NavigationMenu/NavigationMenu.css b/packages/elements/src/components/NavigationMenu/NavigationMenu.css
index cc05bd1..9d114b3 100644
--- a/packages/elements/src/components/NavigationMenu/NavigationMenu.css
+++ b/packages/elements/src/components/NavigationMenu/NavigationMenu.css
@@ -37,6 +37,7 @@ kernel-nav-menu-item {
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/NumberField/NumberField.css b/packages/elements/src/components/NumberField/NumberField.css
index dfb0be3..547fee1 100644
--- a/packages/elements/src/components/NumberField/NumberField.css
+++ b/packages/elements/src/components/NumberField/NumberField.css
@@ -142,6 +142,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/Pagination/Pagination.css b/packages/elements/src/components/Pagination/Pagination.css
index b2ee560..bd93b6f 100644
--- a/packages/elements/src/components/Pagination/Pagination.css
+++ b/packages/elements/src/components/Pagination/Pagination.css
@@ -38,6 +38,7 @@ kernel-pagination-ellipsis {
font-variant-numeric: tabular-nums;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/elements/src/components/RadioGroup/RadioGroup.css b/packages/elements/src/components/RadioGroup/RadioGroup.css
index 01d38da..35aaa96 100644
--- a/packages/elements/src/components/RadioGroup/RadioGroup.css
+++ b/packages/elements/src/components/RadioGroup/RadioGroup.css
@@ -32,6 +32,8 @@
cursor: pointer;
-webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
font-family: var(--kernel-font-sans);
color: var(--kernel-color-text);
}
@@ -108,6 +110,7 @@
}
.kernel-RadioGroup-label {
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/Reasoning/Reasoning.css b/packages/elements/src/components/Reasoning/Reasoning.css
index 5ec6120..a3a10ce 100644
--- a/packages/elements/src/components/Reasoning/Reasoning.css
+++ b/packages/elements/src/components/Reasoning/Reasoning.css
@@ -10,6 +10,7 @@
padding-block: var(--kernel-space-2);
cursor: default;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
}
@@ -65,6 +66,7 @@
.kernel-Reasoning-root[data-state="opening"] .kernel-Reasoning-content,
.kernel-Reasoning-root[data-state="closing"] .kernel-Reasoning-content {
overflow: clip;
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/Resizable/Resizable.css b/packages/elements/src/components/Resizable/Resizable.css
index 86f3203..1fb62a3 100644
--- a/packages/elements/src/components/Resizable/Resizable.css
+++ b/packages/elements/src/components/Resizable/Resizable.css
@@ -15,6 +15,7 @@
}
.kernel-Resizable-root[data-dragging] {
+ -webkit-user-select: none;
user-select: none;
}
@@ -28,6 +29,9 @@
position: relative;
flex-shrink: 0;
background-color: var(--kernel-color-border);
+ -webkit-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/elements/src/components/Select/Select.css b/packages/elements/src/components/Select/Select.css
index 20f0588..ae9963d 100644
--- a/packages/elements/src/components/Select/Select.css
+++ b/packages/elements/src/components/Select/Select.css
@@ -40,6 +40,7 @@
font-size: var(--kernel-font-size-base);
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: border-color var(--kernel-duration-fast) var(--kernel-ease-out),
scale var(--kernel-duration-fast) var(--kernel-ease-out);
diff --git a/packages/elements/src/components/Suggestion/Suggestion.css b/packages/elements/src/components/Suggestion/Suggestion.css
index 7cb2442..785b455 100644
--- a/packages/elements/src/components/Suggestion/Suggestion.css
+++ b/packages/elements/src/components/Suggestion/Suggestion.css
@@ -41,6 +41,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/Switch/Switch.css b/packages/elements/src/components/Switch/Switch.css
index a332c04..746e0b0 100644
--- a/packages/elements/src/components/Switch/Switch.css
+++ b/packages/elements/src/components/Switch/Switch.css
@@ -6,6 +6,8 @@
cursor: pointer;
-webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
font-family: var(--kernel-font-sans);
color: var(--kernel-color-text);
}
@@ -78,6 +80,7 @@
}
.kernel-Switch-label {
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/elements/src/components/Tabs/Tabs.css b/packages/elements/src/components/Tabs/Tabs.css
index 8fa1bea..9bb5bc1 100644
--- a/packages/elements/src/components/Tabs/Tabs.css
+++ b/packages/elements/src/components/Tabs/Tabs.css
@@ -46,6 +46,7 @@ kernel-tabs {
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/TagInput/TagInput.css b/packages/elements/src/components/TagInput/TagInput.css
index 5b52c6c..ea940f3 100644
--- a/packages/elements/src/components/TagInput/TagInput.css
+++ b/packages/elements/src/components/TagInput/TagInput.css
@@ -100,6 +100,8 @@
opacity: 1;
scale: 1;
filter: blur(0);
+ -webkit-user-select: none;
+ user-select: none;
transition:
opacity var(--kernel-duration-exit-fast) linear,
scale var(--kernel-duration-exit-fast) var(--kernel-ease-overlay),
@@ -133,6 +135,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
opacity var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/Toast/Toast.css b/packages/elements/src/components/Toast/Toast.css
index 5bfb30b..c4f142d 100644
--- a/packages/elements/src/components/Toast/Toast.css
+++ b/packages/elements/src/components/Toast/Toast.css
@@ -29,6 +29,7 @@
/* The whole toast is swipe-to-dismiss draggable; without this a drag
gesture starting on its text selects that text instead of moving
the toast. */
+ -webkit-user-select: none;
user-select: none;
--y: 0px;
@@ -196,6 +197,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
opacity: 0.7;
transition:
diff --git a/packages/elements/src/components/Toggle/Toggle.css b/packages/elements/src/components/Toggle/Toggle.css
index 6f22f5b..f4405f9 100644
--- a/packages/elements/src/components/Toggle/Toggle.css
+++ b/packages/elements/src/components/Toggle/Toggle.css
@@ -10,7 +10,10 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/elements/src/components/ToolCall/ToolCall.css b/packages/elements/src/components/ToolCall/ToolCall.css
index 56c0c07..66a752d 100644
--- a/packages/elements/src/components/ToolCall/ToolCall.css
+++ b/packages/elements/src/components/ToolCall/ToolCall.css
@@ -17,6 +17,7 @@
padding-block: var(--kernel-space-2);
cursor: default;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
}
@@ -147,6 +148,7 @@
.kernel-ToolCall-root[data-state="opening"] .kernel-ToolCall-content,
.kernel-ToolCall-root[data-state="closing"] .kernel-ToolCall-content {
overflow: clip;
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/Accordion/Accordion.module.css b/packages/react/src/components/Accordion/Accordion.module.css
index 256984b..3031508 100644
--- a/packages/react/src/components/Accordion/Accordion.module.css
+++ b/packages/react/src/components/Accordion/Accordion.module.css
@@ -25,6 +25,7 @@
list-style: none;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -100,6 +101,7 @@
.item[data-state="opening"] .content,
.item[data-state="closing"] .content {
overflow: clip;
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/Breadcrumbs/Breadcrumbs.module.css b/packages/react/src/components/Breadcrumbs/Breadcrumbs.module.css
index 493dd61..00dcede 100644
--- a/packages/react/src/components/Breadcrumbs/Breadcrumbs.module.css
+++ b/packages/react/src/components/Breadcrumbs/Breadcrumbs.module.css
@@ -42,6 +42,8 @@
color: var(--kernel-color-text-muted);
text-decoration: none;
border-radius: var(--kernel-radius-sm);
+ -webkit-user-select: none;
+ user-select: none;
}
@media (hover: hover) and (pointer: fine) {
diff --git a/packages/react/src/components/Button/Button.module.css b/packages/react/src/components/Button/Button.module.css
index 0eae72b..cf538d1 100644
--- a/packages/react/src/components/Button/Button.module.css
+++ b/packages/react/src/components/Button/Button.module.css
@@ -11,7 +11,10 @@
white-space: nowrap;
text-decoration: none;
cursor: default;
+ -webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
border-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/Carousel/Carousel.module.css b/packages/react/src/components/Carousel/Carousel.module.css
index 9b56e4d..5e3c931 100644
--- a/packages/react/src/components/Carousel/Carousel.module.css
+++ b/packages/react/src/components/Carousel/Carousel.module.css
@@ -56,6 +56,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
@@ -106,6 +107,7 @@
border-radius: var(--kernel-radius-full);
background-color: var(--kernel-color-border-interactive);
cursor: default;
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/react/src/components/Checkbox/Checkbox.module.css b/packages/react/src/components/Checkbox/Checkbox.module.css
index b5d5b77..2d7dc1a 100644
--- a/packages/react/src/components/Checkbox/Checkbox.module.css
+++ b/packages/react/src/components/Checkbox/Checkbox.module.css
@@ -6,6 +6,8 @@
cursor: pointer;
-webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
font-family: var(--kernel-font-sans);
font-size: var(--kernel-font-size-base);
color: var(--kernel-color-text);
diff --git a/packages/react/src/components/CodeBlock/CodeBlock.module.css b/packages/react/src/components/CodeBlock/CodeBlock.module.css
index 40b90e6..f000bf4 100644
--- a/packages/react/src/components/CodeBlock/CodeBlock.module.css
+++ b/packages/react/src/components/CodeBlock/CodeBlock.module.css
@@ -186,8 +186,8 @@
color: var(--kernel-color-text-muted);
font-variant-numeric: tabular-nums;
text-align: end;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
}
.lineText {
diff --git a/packages/react/src/components/Combobox/Combobox.module.css b/packages/react/src/components/Combobox/Combobox.module.css
index 09111e8..0cd2d43 100644
--- a/packages/react/src/components/Combobox/Combobox.module.css
+++ b/packages/react/src/components/Combobox/Combobox.module.css
@@ -121,6 +121,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/CommandPalette/CommandPalette.module.css b/packages/react/src/components/CommandPalette/CommandPalette.module.css
index e673ee4..d487379 100644
--- a/packages/react/src/components/CommandPalette/CommandPalette.module.css
+++ b/packages/react/src/components/CommandPalette/CommandPalette.module.css
@@ -155,6 +155,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/DataTable/DataTable.module.css b/packages/react/src/components/DataTable/DataTable.module.css
index 19cae83..b1fcfdf 100644
--- a/packages/react/src/components/DataTable/DataTable.module.css
+++ b/packages/react/src/components/DataTable/DataTable.module.css
@@ -28,6 +28,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/DatePicker/DatePicker.module.css b/packages/react/src/components/DatePicker/DatePicker.module.css
index 5488882..7aaf38e 100644
--- a/packages/react/src/components/DatePicker/DatePicker.module.css
+++ b/packages/react/src/components/DatePicker/DatePicker.module.css
@@ -36,6 +36,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out), border-color var(--kernel-duration-fast) var(--kernel-ease-out),
scale var(--kernel-duration-fast) var(--kernel-ease-out);
@@ -94,6 +95,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out), color var(--kernel-duration-fast) var(--kernel-ease-out),
scale var(--kernel-duration-fast) var(--kernel-ease-out);
diff --git a/packages/react/src/components/DateRangePicker/DateRangePicker.module.css b/packages/react/src/components/DateRangePicker/DateRangePicker.module.css
index 9d79251..5b2b48a 100644
--- a/packages/react/src/components/DateRangePicker/DateRangePicker.module.css
+++ b/packages/react/src/components/DateRangePicker/DateRangePicker.module.css
@@ -36,6 +36,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out), border-color var(--kernel-duration-fast) var(--kernel-ease-out),
scale var(--kernel-duration-fast) var(--kernel-ease-out);
@@ -103,6 +104,7 @@
cursor: pointer;
/* Also matters here beyond the usual convention: hovering across cells
while previewing/selecting a range must not drag-select day text. */
+ -webkit-user-select: none;
user-select: none;
transition: scale var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/react/src/components/DropdownMenu/DropdownMenu.module.css b/packages/react/src/components/DropdownMenu/DropdownMenu.module.css
index 439b16c..0143a16 100644
--- a/packages/react/src/components/DropdownMenu/DropdownMenu.module.css
+++ b/packages/react/src/components/DropdownMenu/DropdownMenu.module.css
@@ -77,6 +77,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/FileDiff/FileDiff.module.css b/packages/react/src/components/FileDiff/FileDiff.module.css
index b86ae59..e9e7f9f 100644
--- a/packages/react/src/components/FileDiff/FileDiff.module.css
+++ b/packages/react/src/components/FileDiff/FileDiff.module.css
@@ -119,8 +119,8 @@
text-align: end;
vertical-align: top;
white-space: nowrap;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
}
/* The +/− marker is real text, not a colour. Colour alone doesn't say whether
@@ -130,8 +130,8 @@
padding-inline-start: var(--kernel-space-2);
vertical-align: top;
white-space: pre;
- user-select: none;
-webkit-user-select: none;
+ user-select: none;
}
.row[data-kind="add"] .marker {
diff --git a/packages/react/src/components/FileUpload/FileUpload.module.css b/packages/react/src/components/FileUpload/FileUpload.module.css
index 0728af8..b87bcfd 100644
--- a/packages/react/src/components/FileUpload/FileUpload.module.css
+++ b/packages/react/src/components/FileUpload/FileUpload.module.css
@@ -44,6 +44,7 @@
text-align: center;
cursor: pointer;
overflow: hidden;
+ -webkit-user-select: none;
user-select: none;
transition:
border-color var(--kernel-duration-enter) var(--kernel-ease-overlay),
@@ -236,6 +237,7 @@
/* A drag gesture that starts on/near a file row shouldn't fight the
browser's own text-selection heuristics — nothing in the row is
meant to be selected as text. */
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/Label/Label.module.css b/packages/react/src/components/Label/Label.module.css
index b56766b..f610bb7 100644
--- a/packages/react/src/components/Label/Label.module.css
+++ b/packages/react/src/components/Label/Label.module.css
@@ -4,6 +4,8 @@
font-size: var(--kernel-font-size-sm);
font-weight: 500;
color: var(--kernel-color-text);
+ -webkit-user-select: none;
+ user-select: none;
}
.required {
diff --git a/packages/react/src/components/Nav/Nav.module.css b/packages/react/src/components/Nav/Nav.module.css
index 7c60476..91d0a90 100644
--- a/packages/react/src/components/Nav/Nav.module.css
+++ b/packages/react/src/components/Nav/Nav.module.css
@@ -28,6 +28,8 @@
color: var(--kernel-color-text-muted);
text-decoration: none;
font-size: var(--kernel-font-size-sm);
+ -webkit-user-select: none;
+ user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out),
color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/react/src/components/NavigationMenu/NavigationMenu.module.css b/packages/react/src/components/NavigationMenu/NavigationMenu.module.css
index f51f870..a13626c 100644
--- a/packages/react/src/components/NavigationMenu/NavigationMenu.module.css
+++ b/packages/react/src/components/NavigationMenu/NavigationMenu.module.css
@@ -33,6 +33,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out),
color var(--kernel-duration-fast) var(--kernel-ease-out);
diff --git a/packages/react/src/components/NumberField/NumberField.module.css b/packages/react/src/components/NumberField/NumberField.module.css
index 8228f31..78131ca 100644
--- a/packages/react/src/components/NumberField/NumberField.module.css
+++ b/packages/react/src/components/NumberField/NumberField.module.css
@@ -153,6 +153,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/Pagination/Pagination.module.css b/packages/react/src/components/Pagination/Pagination.module.css
index 57545d7..27788a2 100644
--- a/packages/react/src/components/Pagination/Pagination.module.css
+++ b/packages/react/src/components/Pagination/Pagination.module.css
@@ -31,6 +31,7 @@
font-variant-numeric: tabular-nums;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/react/src/components/RadioGroup/RadioGroup.module.css b/packages/react/src/components/RadioGroup/RadioGroup.module.css
index 5b89507..91f957a 100644
--- a/packages/react/src/components/RadioGroup/RadioGroup.module.css
+++ b/packages/react/src/components/RadioGroup/RadioGroup.module.css
@@ -32,6 +32,8 @@
cursor: pointer;
-webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
font-family: var(--kernel-font-sans);
color: var(--kernel-color-text);
}
@@ -108,6 +110,7 @@
}
.label {
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/Reasoning/Reasoning.module.css b/packages/react/src/components/Reasoning/Reasoning.module.css
index c8ccf24..4422b52 100644
--- a/packages/react/src/components/Reasoning/Reasoning.module.css
+++ b/packages/react/src/components/Reasoning/Reasoning.module.css
@@ -22,6 +22,7 @@
padding-block: var(--kernel-space-2);
cursor: default;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
}
@@ -80,6 +81,7 @@
.root[data-state="opening"] .content,
.root[data-state="closing"] .content {
overflow: clip;
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/Resizable/Resizable.module.css b/packages/react/src/components/Resizable/Resizable.module.css
index 06b8685..44438ae 100644
--- a/packages/react/src/components/Resizable/Resizable.module.css
+++ b/packages/react/src/components/Resizable/Resizable.module.css
@@ -15,6 +15,7 @@
}
.root[data-dragging] {
+ -webkit-user-select: none;
user-select: none;
}
@@ -28,6 +29,9 @@
position: relative;
flex-shrink: 0;
background-color: var(--kernel-color-border);
+ -webkit-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
transition: background-color var(--kernel-duration-fast) var(--kernel-ease-out);
}
diff --git a/packages/react/src/components/Select/Select.module.css b/packages/react/src/components/Select/Select.module.css
index 9640269..3d7e94f 100644
--- a/packages/react/src/components/Select/Select.module.css
+++ b/packages/react/src/components/Select/Select.module.css
@@ -40,6 +40,7 @@
font-size: var(--kernel-font-size-base);
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition: border-color var(--kernel-duration-fast) var(--kernel-ease-out),
scale var(--kernel-duration-fast) var(--kernel-ease-out);
diff --git a/packages/react/src/components/Suggestion/Suggestion.module.css b/packages/react/src/components/Suggestion/Suggestion.module.css
index a1a65cb..0038c8f 100644
--- a/packages/react/src/components/Suggestion/Suggestion.module.css
+++ b/packages/react/src/components/Suggestion/Suggestion.module.css
@@ -41,6 +41,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/Switch/Switch.module.css b/packages/react/src/components/Switch/Switch.module.css
index f52bbe8..950d7cb 100644
--- a/packages/react/src/components/Switch/Switch.module.css
+++ b/packages/react/src/components/Switch/Switch.module.css
@@ -6,6 +6,8 @@
cursor: pointer;
-webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
font-family: var(--kernel-font-sans);
color: var(--kernel-color-text);
}
@@ -93,6 +95,7 @@
}
.label {
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/react/src/components/Tabs/Tabs.module.css b/packages/react/src/components/Tabs/Tabs.module.css
index 6964856..fae4503 100644
--- a/packages/react/src/components/Tabs/Tabs.module.css
+++ b/packages/react/src/components/Tabs/Tabs.module.css
@@ -56,6 +56,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/TagInput/TagInput.module.css b/packages/react/src/components/TagInput/TagInput.module.css
index 2ed9334..fb24ef1 100644
--- a/packages/react/src/components/TagInput/TagInput.module.css
+++ b/packages/react/src/components/TagInput/TagInput.module.css
@@ -80,6 +80,8 @@
opacity: 1;
scale: 1;
filter: blur(0);
+ -webkit-user-select: none;
+ user-select: none;
transition:
opacity var(--kernel-duration-exit-fast) linear,
scale var(--kernel-duration-exit-fast) var(--kernel-ease-overlay),
@@ -113,6 +115,7 @@
cursor: pointer;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
transition:
opacity var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/Toast/Toast.module.css b/packages/react/src/components/Toast/Toast.module.css
index c4f5a04..a99c367 100644
--- a/packages/react/src/components/Toast/Toast.module.css
+++ b/packages/react/src/components/Toast/Toast.module.css
@@ -56,6 +56,7 @@
/* The whole toast is swipe-to-dismiss draggable; without this a drag
gesture starting on its text selects that text instead of moving
the toast. */
+ -webkit-user-select: none;
user-select: none;
/* Collapsed default (depth 0, the front toast): no peek offset. Deeper
@@ -270,6 +271,7 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
opacity: 0.7;
transition: opacity var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/Toggle/Toggle.module.css b/packages/react/src/components/Toggle/Toggle.module.css
index 57e91dd..c45b48b 100644
--- a/packages/react/src/components/Toggle/Toggle.module.css
+++ b/packages/react/src/components/Toggle/Toggle.module.css
@@ -10,7 +10,10 @@
cursor: default;
/* Same convention as Button/Checkbox/Switch: a clickable control's
own label text never drag-selects. */
+ -webkit-user-select: none;
user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent;
transition:
background-color var(--kernel-duration-fast) var(--kernel-ease-out),
color var(--kernel-duration-fast) var(--kernel-ease-out),
diff --git a/packages/react/src/components/ToolCall/ToolCall.module.css b/packages/react/src/components/ToolCall/ToolCall.module.css
index 180a251..a83b666 100644
--- a/packages/react/src/components/ToolCall/ToolCall.module.css
+++ b/packages/react/src/components/ToolCall/ToolCall.module.css
@@ -19,6 +19,7 @@
padding-block: var(--kernel-space-2);
cursor: default;
list-style: none;
+ -webkit-user-select: none;
user-select: none;
}
@@ -147,6 +148,7 @@
.root[data-state="opening"] .content,
.root[data-state="closing"] .content {
overflow: clip;
+ -webkit-user-select: none;
user-select: none;
}
diff --git a/packages/styles/src/reset.css b/packages/styles/src/reset.css
index af3f78f..0e01ed2 100644
--- a/packages/styles/src/reset.css
+++ b/packages/styles/src/reset.css
@@ -94,22 +94,57 @@
}
/* Every component already ships its own :hover/:active/:focus-visible
- styling, so the browser's default tap flash and double-tap-to-zoom
- delay only get in the way on touch devices. */
+ styling, so the browser's default tap flash, long-press callout, and
+ double-tap-to-zoom delay only get in the way on touch devices.
+
+ `label` is load-bearing: tapping a checkbox/radio/switch label
+ highlights the LABEL, not the input, so omitting it leaves the
+ grey iOS flash on the most common labelled controls. */
a,
button,
input,
select,
textarea,
summary,
+ label,
[role="button"],
+ [role="checkbox"],
+ [role="combobox"],
[role="menuitem"],
+ [role="menuitemcheckbox"],
+ [role="menuitemradio"],
+ [role="option"],
+ [role="radio"],
+ [role="slider"],
+ [role="switch"],
[role="tab"],
- [role="switch"] {
+ [role="treeitem"] {
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
+ /* Clickable chrome, not editable or copyable content. Links stay
+ selectable (copying the text is a real action) and keep the iOS
+ long-press callout (open in new tab / copy link). Inputs keep
+ selection because that's how you edit them. */
+ button,
+ summary,
+ label,
+ [role="button"],
+ [role="checkbox"],
+ [role="menuitem"],
+ [role="menuitemcheckbox"],
+ [role="menuitemradio"],
+ [role="option"],
+ [role="radio"],
+ [role="switch"],
+ [role="tab"],
+ [role="treeitem"] {
+ -webkit-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
+ }
+
p,
h1,
h2,
diff --git a/scripts/check-shape-pairing.mjs b/scripts/check-shape-pairing.mjs
index 0e291a3..167e988 100644
--- a/scripts/check-shape-pairing.mjs
+++ b/scripts/check-shape-pairing.mjs
@@ -13,10 +13,14 @@
*
* 2. Anything with `cursor: pointer` must also set `user-select: none`.
* Otherwise a double-click on a disclosure selects its own label and a
- * drag from a control selects text across the page.
+ * drag from a control selects text across the page. Any rule that sets
+ * `user-select: none` (or `text`) must also set `-webkit-user-select` to
+ * the same value — Safari still needs the prefix to actually suppress
+ * selection on a double-tap.
*
- * Native form controls are exempt from (2): there's no text in an `` to
- * select. Anything else can opt out with an inline marker naming a reason:
+ * Native form controls are exempt from the cursor:pointer half of (2):
+ * there's no text in an `` to select. Anything else can opt out
+ * with an inline marker naming a reason:
*
* /* shape-pairing-ok: reason *\/
*
@@ -115,6 +119,13 @@ for (const { dir, suffix } of SOURCES) {
}
for (const { selector, body } of rules(css)) {
+ const userSelect = body.match(/user-select:\s*(none|text)/);
+ if (userSelect && !new RegExp(`-webkit-user-select:\\s*${userSelect[1]}`).test(body)) {
+ failures.push(
+ `${relative}: \`${selector}\` sets user-select: ${userSelect[1]} ` +
+ `without -webkit-user-select (see AGENTS.md).`,
+ );
+ }
if (!/cursor:\s*pointer/.test(body)) continue;
if (/user-select:\s*none/.test(body)) continue;
if (isNativeControl(selector, body)) continue;