Skip to content

Conversation

LFDanLu
Copy link
Member

@LFDanLu LFDanLu commented Sep 12, 2025

Also attempts to replace Dialog in S2 Popover so users trying to recreate a Combobox/Autocomplete like experience can simply use Popover

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

Autocomplete behavior should largely be the same as it already is on main, simply sanity check that aria-activedescendant only appears when the wrapped collection support virtual focus. For S2 components that used to use Popover (ComboBox, ContextualHelp, DatePicker, Menu, Picker, TabsPicker) check that their styling and behavior haven't changed with the refactor.

🧢 Your Project:

RSP

// moving focus back to the subtriggers
let isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());
let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;
let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = useState(!isMobileScreenReader && !disableVirtualFocus);
Copy link
Member Author

Choose a reason for hiding this comment

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

We still want to keep disableVirtualFocus as a prop so a user can opt out of the virtual focus behavior based on their use case

Comment on lines +656 to +659
// TODO: Unfortunately can't override via styles prop
// need to unset the overflow otherwise we get two scroll bars
padding: 0,
overflow: 'unset'
Copy link
Member Author

@LFDanLu LFDanLu Sep 12, 2025

Choose a reason for hiding this comment

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

A bit of gross, but needed if we want to completely migrate away from PopoverBase and replace it with Popover now that it directly uses the dialog rendered by RAC Popover. Also a bit annoying that we need to remember to override these...

Comment on lines +106 to +107
// TODO: Unfortunately, we can't pass these styles via the styles prop
// since we don't want to actually allow modifying width and padding for the popover...
Copy link
Member Author

Choose a reason for hiding this comment

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

Since Popover shouldn't freely allow a user to modify its width and padding, there isn't a great way to go about setting those overrides for components using PopoverBase like ContextualHelp...

Copy link
Member Author

Choose a reason for hiding this comment

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

For context, the Popover used to render a Dialog for the user, but this meant Dialog specific behavior like auto focusing the Dialog would make it impossible for a user to use the S2 Popover for a custom Combobox. We've opted to instead rely on RAC Popover applying a "dialog" role instead since users don't have access to PopoverBase

let contextProps;
[contextProps] = useContextProps({}, null, SelectableCollectionContext);
let {filter, ...collectionProps} = contextProps;
[props, ref] = useContextProps(props, ref, SelectableCollectionContext);
Copy link
Member Author

Choose a reason for hiding this comment

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

we now use the ref from useAutocomplete so the Autocomplete input knows it has been connected to a collection element it can filter

@LFDanLu LFDanLu marked this pull request as ready for review September 16, 2025 18:29
@rspbot
Copy link

rspbot commented Sep 16, 2025

@rspbot
Copy link

rspbot commented Sep 16, 2025

@rspbot
Copy link

rspbot commented Sep 16, 2025

## API Changes

react-aria-components

/react-aria-components:SelectableCollectionContext

+SelectableCollectionContext {
+  UNTYPED
+}

/react-aria-components:FieldInputContext

+FieldInputContext {
+  UNTYPED
+}

/react-aria-components:SelectableCollectionContextValue

+SelectableCollectionContextValue <T> {
+  aria-describedby?: string
+  aria-details?: string
+  aria-label?: string
+  aria-labelledby?: string
+  disallowTypeAhead?: boolean
+  filter?: (string, Node<T>) => boolean
+  id?: string
+  shouldUseVirtualFocus?: boolean
+}

@react-aria/utils

/@react-aria/utils:DISALLOW_VIRTUAL_FOCUS

+DISALLOW_VIRTUAL_FOCUS {
+  UNTYPED
+}

@react-spectrum/s2

/@react-spectrum/s2:Popover

 Popover {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
-  children?: ReactNode | (DialogRenderProps) => ReactNode
+  children?: ChildrenOrFunction<PopoverRenderProps>
   containerPadding?: number = 12
   crossOffset?: number = 0
   hideArrow?: boolean = false
   id?: string
   offset?: number = 8
   onOpenChange?: (boolean) => void
   placement?: Placement = 'bottom'
   role?: 'dialog' | 'alertdialog' = 'dialog'
   shouldFlip?: boolean = true
   size?: 'S' | 'M' | 'L'
   slot?: string | null
   styles?: StylesProp
   triggerRef?: RefObject<Element | null>
 }

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

Successfully merging this pull request may close these issues.

2 participants