Skip to content

fix: S2 Selectbox Updates #8748

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

Merged
merged 3 commits into from
Aug 21, 2025
Merged

fix: S2 Selectbox Updates #8748

merged 3 commits into from
Aug 21, 2025

Conversation

DPandyan
Copy link
Collaborator

@DPandyan DPandyan commented Aug 20, 2025

Closes

things to look out for that we discussed when we tested selectbox:

  1. selectbox should have cursor: 'default'. right now it has a pointer cursor
  2. the focus ring should be a halo since it conflicts with the selection state. i think all you need to do is remove the outlineOffset
  3. we're just going to omit the showCheckbox and have checkboxes always rendered. we can change this later
  4. when the user presses down on a select box, the select box should scale down (which is what we call press scaling). search pressScale and example of how to use it in S2 should come up. we want it to look similar to how CardView does when you press down on a Card
  5. clean up the stories a little bit since some of the various states can be achieved by using the controls (like the Disabled one for example). some of stories might actually be better in chromatic where we take snapshots of the components. lemme know if you need help with getting chromatic to work but that can be follow-up to this new PR if it's easier to separate out
  6. spread props onto ListBoxItem/ListBox
  7. delete gutterWidth/numColumns

✅ 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:

Run the SelectBoxGroup.test.tsx file and observe the SelectBox s2 component with yarn start:s2

🧢 Your Project:

@DPandyan
Copy link
Collaborator Author

I still need to take a closer look at the design tokens and the tests but many of the issues have been addressed.

@DPandyan DPandyan changed the title S2 Selectbox Updates WIP: S2 Selectbox Updates Aug 20, 2025
@rspbot
Copy link

rspbot commented Aug 20, 2025

@rspbot
Copy link

rspbot commented Aug 20, 2025

@yihuiliao yihuiliao changed the title WIP: S2 Selectbox Updates fix: S2 Selectbox Updates Aug 20, 2025
render: (args) => {
const {selectionMode, orientation, isDisabled} = args as any;
return (
<SelectBoxGroup selectionMode={selectionMode} orientation={orientation} isDisabled={isDisabled} UNSAFE_style={{gridTemplateColumns: 'repeat(2, 1fr)'}}>
Copy link
Member

Choose a reason for hiding this comment

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

you can just spread args onto here once you have the types fixed

we shouldn't use UNSAFE_style in our documentation, I'd just get rid of it, and if you need to constrain the area so it doesn't go across the entire screen, just add a wrapping div with an appropriate width. Check other storybooks for examples

{/* Enabled items with dynamic illustrations */}
}}
{...args}
UNSAFE_style={{gridTemplateColumns: 'repeat(4, 1fr)'}}>
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

@@ -313,7 +220,7 @@ function InteractiveExamplesStory() {
}

export const InteractiveExamples: Story = {
render: () => <InteractiveExamplesStory />
render: (args) => <InteractiveExamplesStory {...args} />
};

export const AllSlotCombinations: Story = {
Copy link
Member

Choose a reason for hiding this comment

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

this is a better story for chromatic

Comment on lines 91 to 93
jest.spyOn(window.HTMLElement.prototype, 'clientWidth', 'get').mockImplementation(() => 100);
jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get').mockImplementation(() => 100);
jest.spyOn(window.HTMLElement.prototype, 'scrollHeight', 'get').mockImplementation(() => 50);
Copy link
Member

Choose a reason for hiding this comment

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

why do we need to mock all these? this is usually for virtualised components, which this isn't

const options = screen.getAllByRole('option');
const option1 = options.find(option => option.textContent?.includes('Option 1'))!;

await userEvent.click(option1);
await user.click(option1);
Copy link
Member

Choose a reason for hiding this comment

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

We can probably make use of the test-util ListBoxTester in order to do interactions and avoid things like

      const options = screen.getAllByRole('option');
      const option1 = options.find(option => option.textContent?.includes('Option 1'))!;

https://react-spectrum.adobe.com/react-aria/ListBox.html#testing

These three lines would be something like

toggleOptionSelection({option: 1})

Then it's easier to write tests which are agnostic of keyboard or mouse, so you can run both on the same series of tests

francokova

This comment was marked as spam.

Copy link
Member

@reidbarber reidbarber left a comment

Choose a reason for hiding this comment

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

Looks great!

gridTemplateColumns: `repeat(${numColumns}, 1fr)`,
...UNSAFE_style
}}>
{...otherProps}
Copy link
Member

Choose a reason for hiding this comment

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

selectionBehavior="replace" doesn't seem to be working as expected. Probably not something we need to address right now. It seems like something that wouldn't be used with this component anyway.

Copy link
Member

Choose a reason for hiding this comment

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

Also shouldSelectOnPressUp doesn't seem to work as expected. I think this is one we could omit from the types, I don't think it makes sense to have here. A few more aren't working as well, like shouldFocusWrap. Definitely not something we need now though, I would be in favor of omitting them.

Copy link
Member

Choose a reason for hiding this comment

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

Just confirmed with the team that we can omit these props for now.

@rspbot
Copy link

rspbot commented Aug 21, 2025

@rspbot
Copy link

rspbot commented Aug 21, 2025

## API Changes

@react-spectrum/s2

/@react-spectrum/s2:SelectBoxGroup

 SelectBoxGroup <T> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean | FocusStrategy
   children: ReactNode
   className?: ClassNameOrFunction<ListBoxRenderProps>
-  defaultSelectedKeys?: Selection
+  defaultSelectedKeys?: 'all' | Iterable<Key>
+  dependencies?: ReadonlyArray<any>
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
+  dragAndDropHooks?: DragAndDropHooks<NoInfer<T>>
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
-  gutterWidth?: 'default' | 'compact' | 'spacious' = 'default'
   id?: string
   isDisabled?: boolean
-  numColumns?: number = 2
+  items?: Iterable<T>
+  layout?: 'stack' | 'grid' = 'stack'
   onAction?: (Key) => void
   onBlur?: (FocusEvent<Target>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onSelectionChange?: (Selection) => void
   orientation?: Orientation = 'vertical'
-  selectedKeys?: Selection
+  renderEmptyState?: (ListBoxRenderProps) => ReactNode
+  selectedKeys?: 'all' | Iterable<Key>
   selectionBehavior?: SelectionBehavior = "toggle"
   selectionMode?: 'single' | 'multiple' = 'single'
   shouldFocusOnHover?: boolean
   shouldFocusWrap?: boolean
   shouldSelectOnPressUp?: boolean
-  showCheckbox?: boolean = false
   slot?: string | null
   style?: StyleOrFunction<ListBoxRenderProps>
   styles?: StylesProp
 }

/@react-spectrum/s2:SelectBoxGroupProps

 SelectBoxGroupProps <T> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean | FocusStrategy
   children: ReactNode
   className?: ClassNameOrFunction<ListBoxRenderProps>
-  defaultSelectedKeys?: Selection
+  defaultSelectedKeys?: 'all' | Iterable<Key>
+  dependencies?: ReadonlyArray<any>
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
+  dragAndDropHooks?: DragAndDropHooks<NoInfer<T>>
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
-  gutterWidth?: 'default' | 'compact' | 'spacious' = 'default'
   id?: string
   isDisabled?: boolean
-  numColumns?: number = 2
+  items?: Iterable<T>
+  layout?: 'stack' | 'grid' = 'stack'
   onAction?: (Key) => void
   onBlur?: (FocusEvent<Target>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onSelectionChange?: (Selection) => void
   orientation?: Orientation = 'vertical'
-  selectedKeys?: Selection
+  renderEmptyState?: (ListBoxRenderProps) => ReactNode
+  selectedKeys?: 'all' | Iterable<Key>
   selectionBehavior?: SelectionBehavior = "toggle"
   selectionMode?: 'single' | 'multiple' = 'single'
   shouldFocusOnHover?: boolean
   shouldFocusWrap?: boolean
   shouldSelectOnPressUp?: boolean
-  showCheckbox?: boolean = false
   slot?: string | null
   style?: StyleOrFunction<ListBoxRenderProps>
   styles?: StylesProp
 }

Copy link
Member

@reidbarber reidbarber left a comment

Choose a reason for hiding this comment

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

LGTM

@LFDanLu LFDanLu added this pull request to the merge queue Aug 21, 2025
Merged via the queue into main with commit 6b56454 Aug 21, 2025
32 checks passed
@LFDanLu LFDanLu deleted the s2-selectbox-updates branch August 21, 2025 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants