Skip to content

wip: S2 SelectBox Implementation #8541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

wip: S2 SelectBox Implementation #8541

wants to merge 5 commits into from

Conversation

DPandyan
Copy link
Collaborator

Closes #8540

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

🧢 Your Project:

@yihuiliao
Copy link
Member

yihuiliao commented Jul 14, 2025

seems like there's a couple of lint errors, mind running yarn lint and fixing those so we can get a build on the pr? or actually...you might be on a fork but i think we should be able to get you access so that you can directly contribute and we can get builds from you. you might need to ask danni about adding you as a collaborator

@yihuiliao yihuiliao changed the title S2 SelectBox Implementation (WIP) wip: S2 SelectBox Implementation Jul 14, 2025
},
orientation: {
horizontal: {
size: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the value is auto for all the sizes, you can just do:

orientation: {
  horizontal: 'auto'
} 

},
orientation: {
horizontal: {
size: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

},
position: 'relative',
borderWidth: 2,
borderStyle: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
borderStyle: {
borderStyle: 'solid'

borderColor: {
default: 'transparent',
isSelected: 'gray-900',
isFocusVisible: 'transparent'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this needs to go above isSelected since selection should have precedence

allowMultiSelect = false,
size = 'M',
orientation = 'vertical'
} = groupContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can combine this with line 167 since groupContext isnt used anywhere else

* The size of the SelectBoxGroup.
* @default 'M'
*/
size?: 'S' | 'M' | 'L' | 'XL',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to support XS since it's defined in the style macro above

allowMultiSelect: boolean,
children: ReactNode,
style?: React.CSSProperties,
className?: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style and className might need the UNSAFE_ prefix. and you might want to add the styles prop


useEffect(() => {
if (value !== undefined) {
onSelectionChange(value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than call this in a useEffect, create a callback which set on onChange, and in that callback, set the value as well as calling onSelectionChange

@@ -69,6 +69,8 @@ export {Provider} from './Provider';
export {Radio} from './Radio';
export {RadioGroup, RadioGroupContext} from './RadioGroup';
export {RangeCalendar, RangeCalendarContext} from './RangeCalendar';
export {SelectBox} from './SelectBox';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetize

@@ -146,6 +148,8 @@ export type {ProgressCircleProps} from './ProgressCircle';
export type {ProviderProps} from './Provider';
export type {RadioProps} from './Radio';
export type {RadioGroupProps} from './RadioGroup';
export type {SelectBoxProps} from './SelectBox';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetize

label?: ReactNode
}

const SelectorGroup = forwardRef<HTMLDivElement, SelectorGroupProps>(function SelectorGroupComponent({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move this component below the other one so that the file reads as
Top level followed by children/nested


// Simple basic styling with proper dark mode support
const selectBoxStyles = style({
...focusRing(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not sure where the designs for focus rings in select box are currently but i pulled up an older version before they redid all the figma designs to what they are now and the focus ring appears to be like a blue border rather than a outline offset by 2px. you might want to ask design about this

Screenshot 2025-07-15 at 5 25 34 PM


const StarIcon = createIcon(StarSVG);

const meta: Meta<typeof SelectBoxGroup> = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this file to SelectBoxGroup.stories

justifyContent: 'center',
flexShrink: 0,
alignItems: 'center',
fontFamily: 'sans',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since font is already a shorthand for a bunch of other font properties, you don't need to set fontFamily since font already handles it

* The size of the SelectBoxGroup.
* @default 'M'
*/
size?: 'XS' | 'S' | 'M' | 'L' | 'XL',
Copy link
Member

@yihuiliao yihuiliao Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we support XS? checkbox doesn't even have an XS size. i think the checkbox looks too close to the icon(?) when the select box is XS, especially compared to the other sizes.

this also might be good to clarify with design because in the S1 design docs, under Size, the image shows XS but then in the text they say they support four sizes: small, medium, large, and extra-large

<>
{(renderProps.isSelected || renderProps.isHovered || renderProps.isFocusVisible) && (
<div className={checkboxContainer({...renderProps, size}, props.styles)}>
<Checkbox
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one thing i noticed is that if i have selectionMode='single', hover over a SelectBox, and click on the checkbox, nothing happens. however, i would expect that the checkbox be marked as selected.

does this need to be a CheckBox component or can we just style something to look like a checkbox? i don't think having nested label elements is valid. it might cause issues with forms. but also right now, i can keyboard navigate to both the select box and the checkbox inside of it. i'm not sure if that's expected or not

ref
};

return allowMultiSelect ? (
Copy link
Member

@yihuiliao yihuiliao Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

part of me wonders if this should be built using Checkbox/Radios. i say that because the keyboard experience is kinda interesting? for example, it's layout is sorta grid-like, so i would expect that if i arrow down, i would go to the item below but sometimes i go the item to the right due to the nature of how Checkbox/Radio's work

EDIT: that said, not sure what you would use since collections seems a little overkill for something like this

color: {
isDisabled: 'disabled'
}
}, getAllowedOverrides());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think you need getAllowedOverrides here since these aren't styles that can be overridden or changed by the user. the same can be said for textContainer, descriptionText, and contentContainer

return (
<>
{(renderProps.isSelected || renderProps.isHovered || renderProps.isFocusVisible) && (
<div className={checkboxContainer({...renderProps, size}, props.styles)}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should checkboxContainer take props.styles?

/**
* Whether the SelectBoxGroup should be displayed with an emphasized style.
*/
isEmphasized?: boolean,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can't seem to find the designs for an isEmphasized style...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

S2 SelectBox Implementation
4 participants