Repository: Automattic/wp-calypso
Pull request #103073: [DataViews] Enhance filter component styles
Author: login: chihsuan
Created: 2025-05-02T10:50:46Z | Merged: 2025-05-14T08:34:11Z

<!--
Link a related issue to this PR. If the PR does not immediately resolve the issue,
for example, it requires a separate deployment to production, avoid
using the "fixes" keyword and instead attach the [Status] Fix Inbound label to
the linked issue.
-->

Related to WOOA7S-62

## Proposed Changes

* Update the data view filters component to match the design.
  - Use minimal styles for operator select control.
  - Truncate long filter names with ellipses
  - Use radio control for singleSelection type filter (Figma: hdK9XLiOefugy2bxalKBN1-fi-2795_100663)
  - Use checkbox control for multiSelection type filter (Figma: hdK9XLiOefugy2bxalKBN1-fi-2795_101600)
* Use the default WP body font in the storybook styles to make it consistent with the actual styles in the app.


## Why are these changes being made?
<!--
It's easy to see what a PR does but much harder to find out why it was made,
particularly when researching old changes in history. Record an explanation of
the motivation behind this change and how it will help.
-->

* Make the data view filters component consistent with the design so we can use it in the Woo Analytics and other places without additional styling.

## Testing Instructions

<!--
Add as many details as possible to help others reproduce the issue and test the fix.
"Before / After" screenshots can also be very helpful when the change is visual.
-->

* Run `yarn dataviews:storybook:start`
* Go to http://localhost:57863/?path=/story/dataviews-dataviews--default
* Click the filters button to open the filters panel.
* Choose different filters and see if the styles are correct. (Figma: hdK9XLiOefugy2bxalKBN1-fi-2795_90514)
* Change the filter name to a long name and very it doesn't wrap. 
* Change [this line](https://github.com/WordPress/gutenberg/blob/accde16096464ac832fbe8e249a3b61535800800/packages/dataviews/src/components/dataviews-filters/search-widget.tsx#L322) to render `ComboboxList` instead of `ListBox` to see if the combobox list is also working.


Before:

<img width="496" alt="Screenshot 2025-05-02 at 18 41 25" src="https://github.com/user-attachments/assets/325c3797-6127-4be7-9c41-1f08418afb8e" />


<img width="373" alt="Screenshot 2025-05-02 at 18 50 12" src="https://github.com/user-attachments/assets/d925e55c-a6fc-473d-86c7-44bbc1619c6b" />


After

<img width="514" alt="Screenshot 2025-05-02 at 18 37 33" src="https://github.com/user-attachments/assets/0c0095c2-9fc4-40d7-88bd-2a964187dc84" />
<img width="499" alt="Screenshot 2025-05-02 at 18 37 26" src="https://github.com/user-attachments/assets/4d9c5756-3755-45aa-baa5-a561fb38a17f" />
<img width="442" alt="Screenshot 2025-05-02 at 18 36 36" src="https://github.com/user-attachments/assets/b615aa12-4a14-4de4-af30-3510923a3a71" />



## Pre-merge Checklist

<!--
Complete applicable items on this checklist **before** merging into trunk. Inapplicable items can be left unchecked.

Both the PR author and reviewer are responsible for ensuring the checklist is completed.
-->

- [ ] Has the general commit checklist been followed? (PCYsg-hS-p2)
- [ ] [Have you written new tests](https://wpcalypso.wordpress.com/devdocs/docs/testing/index.md) for your changes?
- [ ] Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
- [ ] Have you checked for TypeScript, React or other console errors?
- [ ] Have you used memoizing on expensive computations? More info in [Memoizing with create-selector](https://github.com/Automattic/wp-calypso/blob/trunk/packages/state-utils/src/create-selector/README.md) and [Using memoizing selectors](https://react-redux.js.org/api/hooks#using-memoizing-selectors) and [Our Approach to Data](https://github.com/Automattic/wp-calypso/blob/trunk/docs/our-approach-to-data.md)
- [ ] Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
    - [ ] For UI changes, have we tested the change in various languages (for example, ES, PT, FR, or DE)? The length of text and words vary significantly between languages. 
- [ ] For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?


Diff:
diff --git a/packages/dataviews/.storybook/style.scss b/packages/dataviews/.storybook/style.scss
index 5a0156088d81..bd1dac54239d 100644
--- a/packages/dataviews/.storybook/style.scss
+++ b/packages/dataviews/.storybook/style.scss
@@ -8,3 +8,7 @@
 @import "@wordpress/components/build-style/style";
 
 @import "../src/style.scss";
+
+body {
+	font-family: $font-family-body;
+}
diff --git a/packages/dataviews/CHANGELOG.automattic.md b/packages/dataviews/CHANGELOG.automattic.md
index 6936efbf52f8..4ea99495ef89 100644
--- a/packages/dataviews/CHANGELOG.automattic.md
+++ b/packages/dataviews/CHANGELOG.automattic.md
@@ -5,6 +5,7 @@
 - Add new `boolean` field type definition and edit control. Field type definitions are able to define a default render function that will be used if the field doesn't define one.
 - Pin the actions column on the table view when the width is insufficient.
 - Bring changes from @wordpress/dataviews 4.19.0 (no updates in this version).
+- Enhance filter component styles.
 
 ## 0.1.1
 
diff --git a/packages/dataviews/src/components/dataviews-filters/filter-summary.tsx b/packages/dataviews/src/components/dataviews-filters/filter-summary.tsx
index 7e4c7db9a29a..b57a57c13fa4 100644
--- a/packages/dataviews/src/components/dataviews-filters/filter-summary.tsx
+++ b/packages/dataviews/src/components/dataviews-filters/filter-summary.tsx
@@ -217,6 +217,7 @@ function OperatorSelector( {
 						} );
 					} }
 					size="small"
+					variant="minimal"
 					__nextHasNoMarginBottom
 					hideLabelFromVision
 				/>
diff --git a/packages/dataviews/src/components/dataviews-filters/search-widget.tsx b/packages/dataviews/src/components/dataviews-filters/search-widget.tsx
index 459b68990753..b07e88943bf1 100644
--- a/packages/dataviews/src/components/dataviews-filters/search-widget.tsx
+++ b/packages/dataviews/src/components/dataviews-filters/search-widget.tsx
@@ -4,6 +4,7 @@
 // eslint-disable-next-line no-restricted-imports
 import * as Ariakit from '@ariakit/react';
 import removeAccents from 'remove-accents';
+import clsx from 'clsx';
 
 /**
  * WordPress dependencies
@@ -13,7 +14,6 @@ import { __, sprintf } from '@wordpress/i18n';
 import { useState, useMemo, useDeferredValue } from '@wordpress/element';
 import { VisuallyHidden, Icon, Composite } from '@wordpress/components';
 import { search, check } from '@wordpress/icons';
-import { SVG, Circle } from '@wordpress/primitives';
 
 /**
  * Internal dependencies
@@ -26,12 +26,6 @@ interface SearchWidgetProps {
 	onChangeView: ( view: View ) => void;
 }
 
-const radioCheck = (
-	<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
-		<Circle cx={ 12 } cy={ 12 } r={ 3 }></Circle>
-	</SVG>
-);
-
 function normalizeSearchInput( input = '' ) {
 	return removeAccents( input.trim().toLowerCase() );
 }
@@ -81,6 +75,30 @@ function generateFilterElementCompositeItemId(
 	return `${ prefix }-${ filterElementValue }`;
 }
 
+const MultiSelectionOption = ( { selected }: { selected: boolean } ) => {
+	return (
+		<span
+			className={ clsx(
+				'dataviews-filters__search-widget-listitem-multi-selection',
+				{ 'is-selected': selected }
+			) }
+		>
+			{ selected && <Icon icon={ check } /> }
+		</span>
+	);
+};
+
+const SingleSelectionOption = ( { selected }: { selected: boolean } ) => {
+	return (
+		<span
+			className={ clsx(
+				'dataviews-filters__search-widget-listitem-single-selection',
+				{ 'is-selected': selected }
+			) }
+		/>
+	);
+};
+
 function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
 	const baseId = useInstanceId( ListBox, 'dataviews-filter-list-box' );
 
@@ -189,16 +207,16 @@ function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
 						/>
 					}
 				>
-					<span className="dataviews-filters__search-widget-listitem-check">
-						{ filter.singleSelection &&
-							currentValue === element.value && (
-								<Icon icon={ radioCheck } />
-							) }
-						{ ! filter.singleSelection &&
-							currentValue.includes( element.value ) && (
-								<Icon icon={ check } />
-							) }
-					</span>
+					{ filter.singleSelection && (
+						<SingleSelectionOption
+							selected={ currentValue === element.value }
+						/>
+					) }
+					{ ! filter.singleSelection && (
+						<MultiSelectionOption
+							selected={ currentValue.includes( element.value ) }
+						/>
+					) }
 					<span>{ element.label }</span>
 				</Composite.Hover>
 			) ) }
@@ -288,16 +306,18 @@ function ComboboxList( { view, filter, onChangeView }: SearchWidgetProps ) {
 							setValueOnClick={ false }
 							focusOnHover
 						>
-							<span className="dataviews-filters__search-widget-listitem-check">
-								{ filter.singleSelection &&
-									currentValue === element.value && (
-										<Icon icon={ radioCheck } />
-									) }
-								{ ! filter.singleSelection &&
-									currentValue.includes( element.value ) && (
-										<Icon icon={ check } />
+							{ filter.singleSelection && (
+								<SingleSelectionOption
+									selected={ currentValue === element.value }
+								/>
+							) }
+							{ ! filter.singleSelection && (
+								<MultiSelectionOption
+									selected={ currentValue.includes(
+										element.value
 									) }
-							</span>
+								/>
+							) }
 							<span>
 								<Ariakit.ComboboxItemValue
 									className="dataviews-filters__search-widget-filter-combobox-item-value"
diff --git a/packages/dataviews/src/components/dataviews-filters/style.scss b/packages/dataviews/src/components/dataviews-filters/style.scss
index 130ef8872615..6b2fa72deae7 100644
--- a/packages/dataviews/src/components/dataviews-filters/style.scss
+++ b/packages/dataviews/src/components/dataviews-filters/style.scss
@@ -34,11 +34,10 @@
 }
 
 .dataviews-filters__summary-operators-container {
-	padding: $grid-unit-10 $grid-unit-10 0;
+	padding: $grid-unit-10 $grid-unit-20;
 
 	&:has(+ .dataviews-filters__search-widget-listbox) {
 		border-bottom: 1px solid $gray-200;
-		padding-bottom: $grid-unit-10;
 	}
 
 	&:empty {
@@ -47,6 +46,9 @@
 
 	.dataviews-filters__summary-operators-filter-name {
 		color: $gray-700;
+		white-space: nowrap;
+		overflow: hidden;
+		text-overflow: ellipsis;
 	}
 }
 
@@ -170,9 +172,10 @@
 	gap: $grid-unit-10;
 	border-radius: $radius-small;
 	box-sizing: border-box;
-	padding: $grid-unit-10 $grid-unit-15;
+	padding: $grid-unit-05 $grid-unit-15;
 	cursor: default;
-	margin-block-end: 2px;
+	min-height: $grid-unit-40;
+	@include body-medium();
 
 	&:last-child {
 		margin-block-end: 0;
@@ -184,19 +187,27 @@
 		background-color: var(--wp-admin-theme-color);
 		color: $white;
 
-		.dataviews-filters__search-widget-listitem-check {
-			fill: $white;
-		}
-
 		.dataviews-filters__search-widget-listitem-description {
 			color: $white;
 		}
-	}
 
-	.dataviews-filters__search-widget-listitem-check {
-		width: 24px;
-		height: 24px;
-		flex-shrink: 0;
+		.dataviews-filters__search-widget-listitem-single-selection {
+			border-color: var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
+			background: $white;
+			&.is-selected {
+				border-color: var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
+				background:	var(--wp-components-color-accent-darker-20, var(--wp-admin-theme-color-darker-20, #183ad6));
+			}
+		}
+
+		.dataviews-filters__search-widget-listitem-multi-selection {
+			border-color: var(--wp-admin-theme-color-darker-20, #183ad6);
+
+			&.is-selected {
+				border-color: var(--wp-admin-theme-color-darker-20, #183ad6);
+				background: var(--wp-admin-theme-color-darker-20, #183ad6);
+			}
+		}
 	}
 
 	.dataviews-filters__search-widget-listitem-description {
@@ -207,6 +218,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		@include radio-control;
+		margin: 0;
+		padding: 0;
+
+		&.is-selected {
+			background: var(--wp-admin-theme-color, #3858e9);
+			border-color: var(--wp-admin-theme-color, #3858e9);
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		padding: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-admin-theme-color, #3858e9);
+			border-color: var(--wp-admin-theme-color, #3858e9);
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
 }
 
 .dataviews-filters__search-widget-filter-combobox__wrapper {
diff --git a/packages/dataviews/src/components/dataviews/stories/fixtures.tsx b/packages/dataviews/src/components/dataviews/stories/fixtures.tsx
index bbe4fe6396de..5f1f9ba7e72c 100644
--- a/packages/dataviews/src/components/dataviews/stories/fixtures.tsx
+++ b/packages/dataviews/src/components/dataviews/stories/fixtures.tsx
@@ -667,6 +667,9 @@ export const fields: Field< SpaceObject >[] = [
 			{ value: 'Terrestrial', label: 'Terrestrial' },
 			{ value: 'Gas giant', label: 'Gas giant' },
 		],
+		filterBy: {
+			operators: [ 'is', 'isNot' ],
+		},
 	},
 	{
 		id: 'isPlanet',


Reviews:
user: login: ciampo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T14:55:28Z
user: login: chihsuan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-09T06:09:02Z
user: login: youknowriad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:15:55Z
user: login: chihsuan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T06:14:44Z
user: login: chihsuan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T06:15:04Z
user: login: youknowriad
body: Let's document this change in the changelog and give it a try.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T07:58:21Z
user: login: ciampo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T15:55:58Z
user: login: chihsuan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T01:02:42Z
user: login: ciampo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T13:01:03Z
user: login: chihsuan
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T03:45:35Z

Review comments:
diff_hunk: @@ -81,6 +75,30 @@ function generateFilterElementCompositeItemId(
 	return `${ prefix }-${ filterElementValue }`;
 }
 
+const Checkbox = ( { checked }: { checked: boolean } ) => {
+	return (
+		<span
+			className={ clsx(
+				'dataviews-filters__search-widget-listitem-checkbox',
+				{ 'is-checked': checked }
+			) }
+		>
+			{ checked && <Icon icon={ check } /> }
+		</span>
+	);
+};
+
+const Radio = ( { checked }: { checked: boolean } ) => {
+	return (
+		<span
+			className={ clsx(
+				'dataviews-filters__search-widget-listitem-radio',
+				{ 'is-checked': checked }
+			) }
+		/>
+	);
+};
+
path: packages/dataviews/src/components/dataviews-filters/search-widget.tsx
user: login: ciampo
body: Calling these two components "checkbox" and "radio" implies the wrong abstraction and semantics ([Checkbox](https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/) and [Radio](https://www.w3.org/WAI/ARIA/apg/patterns/radio/) semantics are different from [listbox semantics](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/) ).

These should likely be called something like `SingleSelectionOption` and `MultiSelectionOption`, or something similar, and have a `selected` prop (instead of `checked`). Classnames should follow similar naming, too.
created_at: 2025-05-08T14:55:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -81,6 +75,30 @@ function generateFilterElementCompositeItemId(
 	return `${ prefix }-${ filterElementValue }`;
 }
 
+const Checkbox = ( { checked }: { checked: boolean } ) => {
+	return (
+		<span
+			className={ clsx(
+				'dataviews-filters__search-widget-listitem-checkbox',
+				{ 'is-checked': checked }
+			) }
+		>
+			{ checked && <Icon icon={ check } /> }
+		</span>
+	);
+};
+
+const Radio = ( { checked }: { checked: boolean } ) => {
+	return (
+		<span
+			className={ clsx(
+				'dataviews-filters__search-widget-listitem-radio',
+				{ 'is-checked': checked }
+			) }
+		/>
+	);
+};
+
path: packages/dataviews/src/components/dataviews-filters/search-widget.tsx
user: login: chihsuan
body: Thanks for the feedback! I've updated the code to use the suggested naming and semantics in 76617fcac6e7b7310d9f6455690edcf5f0bdd5a3.
created_at: 2025-05-09T06:09:02Z
author_association: MEMBER
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: youknowriad
body: There's a lot of CSS variables used here. Do we know where these CSS variables are being defined? Is it all in `@wordpress/components`? It is ok for the dataviews package to rely on wordpress/components but some of these might be considered internal APIs for now.

cc @ciampo for confirmation.

created_at: 2025-05-12T07:15:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: chihsuan
body: >  Do we know where these CSS variables are being defined? Is it all in @wordpress/components?

`--wp-components-color-*` variables are all defined in `@wordpress/components`. They are provided by the [`<Theme>`](
https://github.com/WordPress/gutenberg/blob/trunk/packages/components/src/theme/styles.ts#L12-L31) component.

However, I found that it's not being used in production. It seems that it's only available in the @wordpress/components storybook. I'll update the PR to remove the references to these variables.

For the other CSS variables:

- `--wp-admin-theme-color-*` variables are defined in Core
- Other CSS variables like `--checkmark-size` are defined locally within the same file.



created_at: 2025-05-13T06:14:44Z
author_association: MEMBER
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: chihsuan
body: Updated in 4bcbb9979b933f4f2454e39b07727c90875dbfd1.
created_at: 2025-05-13T06:15:04Z
author_association: MEMBER
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: ciampo
body: Excuses for the delay in answering, I've been catching up on pings after some very busy weeks.

As Riad suggests, `--wp-components-color-*` are meant as internal variables of the `@wordpress/components` package. They are not advertised as public APIs, we disocurage its use [in the `Theme` README](https://github.com/WordPress/gutenberg/blob/trunk/packages/components/src/theme/README.md?plain=1#L31), and in Gutenberg we had set up [a stylelint rule](https://github.com/WordPress/gutenberg/blob/d7e0c5d872ba82d851c696cc4c67ea84368a5224/.stylelintrc.js#L23) to prevent their usage.

Could we work on a follow-up PR to remove usage of these variables? (cc @mirka)
created_at: 2025-05-20T15:55:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: chihsuan
body: 
Thanks for checking on this.

The `--wp-components-color-*` variables were already removed in commit 4bcbb99 prior to the PR being merged. Let me know if anything is missing. 
created_at: 2025-05-21T01:02:42Z
author_association: MEMBER
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: ciampo
body: Looking at the merged code, I can still see instances of those variables in `packages/dataviews/src/components/dataviews-filters/style.scss` — those are the ones I was referring to
created_at: 2025-05-21T13:01:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -207,6 +211,81 @@
 		line-height: 16px;
 		color: $gray-700;
 	}
+
+	.dataviews-filters__search-widget-listitem-single-selection {
+		$components-color-accent: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+		@include radio-control;
+		margin: 0;
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			&::before {
+				content: "";
+				border-radius: $radius-round;
+				box-sizing: inherit;
+				width: math.div($radio-input-size-sm, 2);
+				height: math.div($radio-input-size-sm, 2);
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				margin: 0;
+				background-color: $white;
+
+				// This border serves as a background color in Windows High Contrast mode.
+				border: 4px solid $white;
+
+				@include break-small() {
+					width: math.div($radio-input-size, 2);
+					height: math.div($radio-input-size, 2);
+				}
+			}
+		}
+	}
+
+	.dataviews-filters__search-widget-listitem-multi-selection {
+		--checkbox-size: 24px; // Width & height for small viewports.
+
+		@include checkbox-control;
+		position: relative;
+		background: $white;
+		color: $gray-900;
+		margin: 0;
+		width: var(--checkbox-size);
+		height: var(--checkbox-size);
+
+		@include break-small() {
+			--checkbox-size: 16px;
+		}
+
+		@media not (prefers-reduced-motion) {
+			transition: 0.1s border-color ease-in-out;
+		}
+
+		&.is-selected {
+			background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+			border-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
+
+			svg {
+				--checkmark-size: var(--checkbox-size);
+
+				fill: $white;
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				width: var(--checkmark-size);
+				height: var(--checkmark-size);
+
+				@include break-small() {
+					--checkmark-size: calc(var(--checkbox-size) + 4px);
+				}
+			}
+		}
+	}
path: packages/dataviews/src/components/dataviews-filters/style.scss
user: login: chihsuan
body: Thanks for catching this. 🙏  I've opened a new PR to remove them. https://github.com/Automattic/wp-calypso/pull/103615
created_at: 2025-05-22T03:45:34Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-02T10:51:00Z
body: <details>
<summary>Calypso Live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144185">(direct link)</a></summary>
<table>
<tr>
<td>
<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=https%3A%2F%2Fcalypso.live%3Fimage%3Dregistry.a8c.com%2Fcalypso%2Fapp%3Abuild-144185%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144185">https://calypso.live?image=registry.a8c.com/calypso/app:build-144185</a>
</td>
</tr>
</table>
</details>
<details>
<summary>Jetpack Cloud live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144185&env=jetpack">(direct link)</a></summary>
<table>
<tr>
<td>
<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=https%3A%2F%2Fcalypso.live%3Fimage%3Dregistry.a8c.com%2Fcalypso%2Fapp%3Abuild-144185%26env%3Djetpack%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144185&env=jetpack">https://calypso.live?image=registry.a8c.com/calypso/app:build-144185&env=jetpack</a>
</td>
</tr>
</table>
</details>
<details>
<summary>Automattic for Agencies live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144185&env=a8c-for-agencies">(direct link)</a></summary>
<table>
<tr>
<td>
<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=https%3A%2F%2Fcalypso.live%3Fimage%3Dregistry.a8c.com%2Fcalypso%2Fapp%3Abuild-144185%26env%3Da8c-for-agencies%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144185&env=a8c-for-agencies">https://calypso.live?image=registry.a8c.com/calypso/app:build-144185&env=a8c-for-agencies</a>
</td>
</tr>
</table>
</details>
<!--calypso-live-watermark:apr@v1-->
author_association: NONE
user: login: matticbot
created_at: 2025-05-02T10:59:22Z
body: **This PR modifies the release build for the following Calypso Apps:**

_For info about this notification, see here: PCYsg-OT6-p2_

* notifications
* wpcom-block-editor

To test WordPress.com changes, run `install-plugin.sh $pluginSlug wooa7s-62-single-report-filters-enhance-filter-summary-component-style` on your sandbox.
<!--calypso-app-artifacts-watermark:apr@v1-->
author_association: CONTRIBUTOR
user: login: matticbot
created_at: 2025-05-02T11:00:51Z
body: <!-- icfy-watermark: c52822 -->
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

**Sections** (~41 bytes removed 📉 [gzipped])
<details>

```
name                parsed_size           gzip_size
staging-site              -52 B  (-0.0%)      -41 B  (-0.0%)
sites-dashboard           -52 B  (-0.0%)      -41 B  (-0.0%)
site-settings             -52 B  (-0.0%)      -41 B  (-0.0%)
site-performance          -52 B  (-0.0%)      -41 B  (-0.0%)
site-monitoring           -52 B  (-0.0%)      -41 B  (-0.0%)
site-logs                 -52 B  (-0.0%)      -41 B  (-0.0%)
plans                     -52 B  (-0.0%)      -41 B  (-0.0%)
overview                  -52 B  (-0.0%)      -41 B  (-0.0%)
hosting                   -52 B  (-0.0%)      -41 B  (-0.0%)
github-deployments        -52 B  (-0.0%)      -41 B  (-0.0%)
domains                   -52 B  (-0.0%)      -41 B  (-0.0%)
```

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.
</details>

**Legend**
<details>
<summary>What is parsed and gzip size?</summary>

**Parsed Size:** Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
**Gzip Size:** Compressed size of the JS and CSS files. This much data needs to be downloaded over network.
</details>

Generated by performance advisor bot at [iscalypsofastyet.com](http://iscalypsofastyet.com).
author_association: CONTRIBUTOR
user: login: jameskoster
created_at: 2025-05-02T15:38:31Z
body: <!-- linear:isThreadRoot -->

Thanks for the ping, this is a nice enhancement! 🙂 

I think we need some technical feedback from the components team about the use of checkbox/radio inputs within the `listbox`. Generally the individual `option` elements are expected to be single interactive units. 

> In addition, the interaction model conveyed by the listbox role to assistive technologies *does not support interacting with elements inside of an option*.<br>—[w3.org](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/)

My interpretation (could be wrong), is that nesting form elements could be confusing to users of certain assistive tech.

That's not to say we shouldn't employ the design, just that we may need to think differently about the implementation. Instead of using inputs, maybe we style non-interactive elements to *look* like inputs?

That leads neatly onto the next point; using inputs leads to some awkwardly styled states, e.g.:

<img src="https://uploads.linear.app/f629fcde-6f9b-48e8-8af3-60eed8823bff/23990f11-85d1-48f6-9167-1cba4345c3df/c2fa0561-1259-4063-9231-b2fc0d7c6b04?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2Y2MjlmY2RlLTZmOWItNDhlOC04YWYzLTYwZWVkODgyM2JmZi8yMzk5MGYxMS04NWQxLTQ4ZjYtOTE2Ny0xY2JhNDM0NWMzZGYvYzJmYTA1NjEtMTI1OS00MDYzLTkyMzEtYjJmYzBkN2M2YjA0IiwiaWF0IjoxNzQ2MjAwMzEwLCJleHAiOjMzMzE2NzYwMzEwfQ.vheMoPCODe-dLUv_vnDp_D0DVjLrmfPLeGgi4pR_ATU " alt="Screenshot 2025-05-02 at 16.31.26.png" width="258" data-linear-height="54" />

I think it would be beneficial to mock up the intended designs for all `option` states, for both multi-select (checkbox) and single-select (radio) listboxes. I may be wrong, but I think @<!-- linear:userMention:882ce9d9-ab24-45bb-8e9e-186735b72984 -->veronica.fasulo may have worked on this already (apologies for the ping if not).
author_association: CONTRIBUTOR
user: login: chihsuan
created_at: 2025-05-05T06:04:52Z
body: <!-- linear:replyTo:2847520674 -->

Thanks for the review and feedback! Jay.

> I think we need some technical feedback from the components team about the use of checkbox/radio inputs within the listbox. Generally the individual option elements are expected to be single interactive units.<br>Instead of using inputs, maybe we style non-interactive elements to look like inputs?  Good point!

I agree that using non-interactive elements would be a better approach for accessibility. I'll update the implementation accordingly. 🙂 

> I think it would be beneficial to mock up the intended designs for all `option` states, for both multi-select (checkbox) and single-select (radio) listboxes. 

@<!-- linear:userMention:882ce9d9-ab24-45bb-8e9e-186735b72984 -->veronica.fasulo  If we have a mockup for all option states, could you share it here? 🙏 I'll double-check the styles and make sure they're applied correctly. Thanks!
author_association: MEMBER
user: login: chihsuan
created_at: 2025-05-05T07:44:07Z
body: <!-- linear:isThreadRoot -->

I've replaced RadioControl and CheckboxControl with custom non-interactive implementations in daf756917dbc8ac9f892ee01fb88213d4baa2775.

https://github.com/user-attachments/assets/c2a8c3da-a22e-4ee1-b4da-620aa393697d


author_association: MEMBER
user: login: youknowriad
created_at: 2025-05-07T08:29:47Z
body: While I'm ok shipping this as interim step, I think there's a discussion to be had about whether "listbox" is the right thing rather than just considering the dropdown as a regular form with any form controls. There's also a world where the same controls from all the filters should also be rendered in a sidebar (I know there were design explorations like that). Maybe something for a separate issue.
author_association: CONTRIBUTOR
user: login: youknowriad
created_at: 2025-05-07T08:30:36Z
body: @oandregal Any thoughts here?
author_association: CONTRIBUTOR
user: login: chihsuan
created_at: 2025-05-07T09:50:39Z
body: @jameskoster 👋 


I've checked with @verofasulo (p1746587859135169/1746587662.284489-slack-C06FSDTSN82) and we've confirmed that implementing hover state changes for checkbox/radio options is not required - specifically, we don't need background color changes on hover.

So, it would be like this:


https://github.com/user-attachments/assets/587005e3-41fa-4dbd-b132-9872dae662e7


What do you think about this?
author_association: MEMBER
user: login: jameskoster
created_at: 2025-05-07T11:35:36Z
body: <!-- linear:replyTo:2850169950 -->

@chihsuan that looks pretty good to me. My one suggestion would be to somehow indicate that the entire row is interactive. That could be a hover style, or just changing the cursor to `pointer`. 

How does the appearance look as you navigate via keyboard? We need to highlight the 'focussed' option some how. We could probably use the aforementioned hover style to handle that.
author_association: CONTRIBUTOR
user: login: jameskoster
created_at: 2025-05-07T11:41:39Z
body: > I think there's a discussion to be had about whether "listbox" is the right thing rather than just considering the dropdown as a regular form with any form controls

From the design perspective I'm leaning slightly toward using `listbox` over forms because it offers a stronger UX from an accessibility standpoint, and it's more flexible for enhancements like building a `combobox`. Would this not be compatible with the sidebar filter design?
author_association: CONTRIBUTOR
user: login: youknowriad
created_at: 2025-05-07T12:45:49Z
body: My thinking is more global. Filters are forms, some will have date range picker, others will have select box, some will have radio control, others multiple checkboxes. `listbox` is fine in a form, it's just a select box with images but in that case, if we want to use a list box, I don't think we should be imitating the look and feel of checkboxes and radioboxes. Just my 2cts. 
author_association: CONTRIBUTOR
user: login: chihsuan
created_at: 2025-05-08T07:40:26Z
body: > that looks pretty good to me. My one suggestion would be to somehow indicate that the entire row is interactive. That could be a hover style, or just changing the cursor to `pointer`.

Changing the cursor to `pointer` makes sense to me. cc @verofasulo What do you think?

> How does the appearance look as you navigate via keyboard? We need to highlight the 'focussed' option some how. We could probably use the aforementioned hover style to handle that.

Yeah, we need to highlight the focused option somehow. We could maintain the current focus styles for keyboard navigation to ensure accessibility.

https://github.com/user-attachments/assets/b0fdb55b-a135-42c8-8447-e2d5df5b9c7f


author_association: MEMBER
user: login: jameskoster
created_at: 2025-05-08T11:00:58Z
body: <!-- linear:replyTo:2850169950 -->

It's nit-picking territory but there's something slightly off about the selected checkbox blending into the highlight style. Could it make sense to set the selected checkbox background to `--wp-components-color-accent-darker-10` when the option is highlighted? That way the checkbox footprint remains visible. 
author_association: CONTRIBUTOR
user: login: jasmussen
created_at: 2025-05-08T11:04:02Z
body: Good nitpick, though. 🤔 

A darkening can work, yes, especially in absence of a larger revisit of the "selected item" style, where the total inversion feels fairly hefty. 
author_association: MEMBER
user: login: jameskoster
created_at: 2025-05-08T11:09:15Z
body: <!-- linear:replyTo:2850169950 -->

> if we want to use a list box, I don't think we should be imitating the look and feel of checkboxes and radioboxes

It may be important to unpack that as it's basically the whole point of the PR 😀 Noting that @ciampo surfaced similar concerns in [https://github.com/WordPress/gutenberg/issues/65801#issuecomment-2388739111](https://github.com/WordPress/gutenberg/issues/65801#issuecomment-2388739111).<br><br>I don't have a strong opinion on this one. I see the UX argument (feel free to correct me on this @<!-- linear:userMention:882ce9d9-ab24-45bb-8e9e-186735b72984 -->veronica.fasulo); without a visual cue it's not clear whether a listbox is single or multi-select. Using checkbox/radio appearance provides this clarity. But I acknowledge it may also be confusing because we're presenting two (subtly) different behaviors in an identical way.
author_association: CONTRIBUTOR
user: login: oandregal
created_at: 2025-05-08T11:14:16Z
body: I've noticed this introduces horizontal scroll with long field labels:

https://github.com/user-attachments/assets/46a66209-d431-4404-bb1b-e9b3d7018fba


author_association: CONTRIBUTOR
user: login: oandregal
created_at: 2025-05-08T11:27:18Z
body: It maintains the same keyboard behavior (space key has press behavior, navigate through the items with the arrows keys, focus is contained to the list until you tab, etc.). That's good.

Just noting this will affect every product: so, style-wise, as long as is design-blessed, it's good for me. I do appreciate the ability to understand what'll happen before I interact with the widget (single vs multi selection), to be honest.

It feels weird that we are making them _look like_ the real components. I understand we don't want to use the real ones because we are using the listbox instead of a form — is that hinting at something we should address? I don't have a formed opinion on this just yet. I'd like to hear @ciampo @mirka thoughts before landing this PR.

author_association: CONTRIBUTOR
user: login: ciampo
created_at: 2025-05-08T14:50:56Z
body: I've been thinking about it, and probably the main aspect I'd like to avoid is to use _both_ radio and checkbox UI language (for single vs multi selection).

Instead, we could always use the checkbox tick, but use a different visual treatment to hint at single vs multiple selection. For example, take a look at [the `OptionList` component from polaris](https://polaris.shopify.com/components/lists/option-list):

Single:

![Screenshot 2025-05-08 at 16 49 49](https://github.com/user-attachments/assets/4b5d670d-973b-437c-b3d3-51ea10d52cb3)

Multiple:
![Screenshot 2025-05-08 at 16 50 01](https://github.com/user-attachments/assets/376c8090-d8da-4bb0-b0e2-a6fc77d3b063)


This behaviour could also be applied to other components where we use listbox/checkbox/radio semantics like `Menu`(ie. use a similar visual treatment for checkbox vs radio menu items), although it may need more thinking to make sure it's a good visual abstraction.

author_association: CONTRIBUTOR
user: login: chihsuan
created_at: 2025-05-09T06:08:34Z
body: > Could it make sense to set the selected checkbox background to `--wp-components-color-accent-darker-10` when the option is highlighted? That way the checkbox footprint remains visible.

I've changed the selected background color in 52c4f30a94ab6bc428ac981da8461470c5640301. Is it looking good?

<img width="253" alt="Screenshot 2025-05-09 at 13 41 20" src="https://github.com/user-attachments/assets/0c3adafe-cd2a-4dc0-ab20-ad4e64c1398d" />

author_association: MEMBER
user: login: chihsuan
created_at: 2025-05-09T06:24:06Z
body: > I've noticed this introduces horizontal scroll with long field labels:

We could set a max-width to the label element to prevent horizontal scrolling with long field labels. Would it make sense to set a max-width of 60% for label?

author_association: MEMBER
user: login: jameskoster
created_at: 2025-05-09T12:17:25Z
body: <!-- linear:replyTo:2850169950 -->

@ciampo how about leaving single-select as it is (dot):

<img src="https://uploads.linear.app/f629fcde-6f9b-48e8-8af3-60eed8823bff/c8265a3d-9848-408e-b29c-4fcedec0e16e/60781caa-32db-4e50-a47c-382e4f5c4971?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2Y2MjlmY2RlLTZmOWItNDhlOC04YWYzLTYwZWVkODgyM2JmZi9jODI2NWEzZC05ODQ4LTQwOGUtYjI5Yy00ZmNlZGVjMGUxNmUvNjA3ODFjYWEtMzJkYi00ZTUwLWE0N2MtMzgyZTRmNWM0OTcxIiwiaWF0IjoxNzQ2NzkzMDQ1LCJleHAiOjMzMzE3MzUzMDQ1fQ.bxVYQv38w3B68i77KnA5dsfBMHhWPt1sfmhZXIJ5FDQ " alt="Screenshot 2025-05-09 at 13.15.50.png" width="300" data-linear-height="167" />

Then adding the pseudo-checkbox to multi-select? 
author_association: CONTRIBUTOR
user: login: jameskoster
created_at: 2025-05-09T12:25:04Z
body: <!-- linear:replyTo:2850169950 -->

@chihsuan Maybe `--wp-components-color-accent-darker-20` would be better (sorry!). I suppose we could use the same color for the deselected checkbox border when hovering too.

<img src="https://uploads.linear.app/f629fcde-6f9b-48e8-8af3-60eed8823bff/3381ab5e-f58d-4bbd-8a9c-f6304311c5ca/13972172-cd4a-4001-a117-ff131ab5607d?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2Y2MjlmY2RlLTZmOWItNDhlOC04YWYzLTYwZWVkODgyM2JmZi8zMzgxYWI1ZS1mNThkLTRiYmQtOGE5Yy1mNjMwNDMxMWM1Y2EvMTM5NzIxNzItY2Q0YS00MDAxLWExMTctZmYxMzFhYjU2MDdkIiwiaWF0IjoxNzQ2NzkzNTAzLCJleHAiOjMzMzE3MzUzNTAzfQ.qJ1m-Xy7G2q41yTO6NAwSfGSKSaDeIjOzPe020cpy-0 " alt="Screenshot 2025-05-09 at 13.24.45.png" width="858" data-linear-height="360" />
author_association: CONTRIBUTOR
user: login: chihsuan
created_at: 2025-05-12T07:03:31Z
body: > Maybe `--wp-components-color-accent-darker-20` would be better (sorry!). I suppose we could use the same color for the deselected checkbox border when hovering too.

 @jameskoster Sounds good. I've updated the PR to use `--wp-components-color-accent-darker-20` for the multi-selection hover/focus state.

<img width="325" alt="Screenshot 2025-05-12 at 15 00 08" src="https://github.com/user-attachments/assets/f03a6260-2993-414f-83a1-4f46ecf764aa" />
<img width="313" alt="Screenshot 2025-05-12 at 15 00 03" src="https://github.com/user-attachments/assets/e3474f60-82b2-49d2-ac83-1516afadd0a3" />

author_association: MEMBER
user: login: jameskoster
created_at: 2025-05-12T14:22:41Z
body: <!-- linear:replyTo:2850169950 -->

@chihsuan I pushed a couple of small style tweaks, hope that's okay. I fixed the dimensions of the 'checkbox' and 'radio' elements, set the height of each list item to be a minimum of `32px`, and adjusted the radio hover appearance slightly to better align with the checkbox.
author_association: CONTRIBUTOR
user: login: chihsuan
created_at: 2025-05-13T02:43:10Z
body: > @chihsuan I pushed a couple of small style tweaks, hope that's okay. I fixed the dimensions of the 'checkbox' and 'radio' elements, set the height of each list item to be a minimum of `32px`, and adjusted the radio hover appearance slightly to better align with the checkbox.

@jameskoster That's great, thank you! 🙂 
author_association: MEMBER
user: login: chihsuan
created_at: 2025-05-14T08:32:10Z
body: Added changelog in 7f334ce0fa6d55caf63b7b76bb195f88a9697d98

Thank you all for your feedback.

author_association: MEMBER