Skip to content

docs: shouldCloseOnSelect, interactOutsideBehavior, and new viewport css vars #9855

Merged
LFDanLu merged 6 commits intomainfrom
audit_stuff
Mar 30, 2026
Merged

docs: shouldCloseOnSelect, interactOutsideBehavior, and new viewport css vars #9855
LFDanLu merged 6 commits intomainfrom
audit_stuff

Conversation

@LFDanLu
Copy link
Copy Markdown
Member

@LFDanLu LFDanLu commented Mar 27, 2026

Part of release audit, open to opinions if these should be added or not

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

RSP

@github-actions github-actions bot added the S2 label Mar 27, 2026
@rspbot
Copy link
Copy Markdown

rspbot commented Mar 27, 2026

reidbarber
reidbarber previously approved these changes Mar 27, 2026
</RangeCalendar>
```

## Interact outside behavior
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd be ok just having this in the prop table, not sure what other people think.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

agree. Add it as a prop control to the top example as well.

@rspbot
Copy link
Copy Markdown

rspbot commented Mar 27, 2026

@LFDanLu LFDanLu added documentation Improvements or additions to documentation ready for review labels Mar 28, 2026

## Interact outside behavior

Use the `interactOutsideBehavior` prop to control what happens when a range selection is in progress and the user interacts outside the calendar.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Use the `interactOutsideBehavior` prop to control what happens when a range selection is in progress and the user interacts outside the calendar.
Use the `interactOutsideBehavior` prop to control what happens when a range selection is in progress and the user interacts outside the available dates.


## Interact outside behavior

Use the `interactOutsideBehavior` prop to control what happens when a range selection is in progress and the user interacts outside the calendar.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same

@rspbot
Copy link
Copy Markdown

rspbot commented Mar 30, 2026


<ExampleSwitcher>
```tsx render docs={vanillaDocs.exports.Select} links={docs.links} props={['label', 'placeholder', 'selectionMode', 'isDisabled']} initialProps={{label: 'Favorite Animal'}} type="vanilla" files={["starters/docs/src/Select.tsx", "starters/docs/src/Select.css"]}
```tsx render docs={vanillaDocs.exports.Select} links={docs.links} props={['label', 'placeholder', 'selectionMode', 'isDisabled', 'shouldCloseOnSelect']} initialProps={{label: 'Favorite Animal', shouldCloseOnSelect: true}} type="vanilla" files={["starters/docs/src/Select.tsx", "starters/docs/src/Select.css"]}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This results in weird behavior because then multi-select will also close on select which is not the default. I say just omit this. It's a rare use case.

@rspbot
Copy link
Copy Markdown

rspbot commented Mar 30, 2026

@rspbot
Copy link
Copy Markdown

rspbot commented Mar 30, 2026

## API Changes

react-aria-components

/react-aria-components:TableLayout

 TableLayout <O extends TableLayoutProps = TableLayoutProps, T> {
-  constructor: (TableLayoutProps) => void
+  constructor: (ListLayoutOptions) => void
   getContentSize: () => Size
   getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget | null
   getDropTargetLayoutInfo: (ItemDropTarget) => LayoutInfo
   getLayoutInfo: (Key) => LayoutInfo | null
   shouldInvalidate: (Rect, Rect) => boolean
   shouldInvalidateLayoutOptions: (TableLayoutProps, TableLayoutProps) => boolean
   update: (InvalidationContext<TableLayoutProps>) => void
   updateItemSize: (Key, Size) => boolean
   useLayoutOptions: () => TableLayoutProps
   virtualizer: Virtualizer<{}, any> | null
 }

/react-aria-components:ListLayoutOptions

 ListLayoutOptions {
   dropIndicatorThickness?: number = 2
-  estimatedHeadingSize?: number
-  estimatedRowSize?: number
+  estimatedHeadingHeight?: number
+  estimatedRowHeight?: number
   gap?: number = 0
-  headingSize?: number = 48
-  loaderSize?: number = 48
+  headingHeight?: number = 48
+  loaderHeight?: number = 48
   orientation?: Orientation = 'vertical'
   padding?: number = 0
-  rowSize?: number = 48
+  rowHeight?: number = 48
 }

/react-aria-components:TableLayoutProps

-TableLayoutProps {
-  columnWidths?: Map<Key, number>
-  dropIndicatorThickness?: number = 2
-  estimatedHeadingHeight?: number
-  estimatedRowHeight?: number
-  gap?: number = 0
-  headingHeight?: number = 48
-  loaderHeight?: number = 48
-  padding?: number = 0
-  rowHeight?: number = 48
-}

@react-spectrum/s2

/@react-spectrum/s2:DateRangePicker

 DateRangePicker <T extends DateValue> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   allowsNonContiguousRanges?: boolean
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   createCalendar?: (CalendarIdentifier) => Calendar
   defaultOpen?: boolean
   defaultValue?: RangeValue<DateValue> | null
   description?: ReactNode
   endName?: string
   errorMessage?: ReactNode
   firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'
   form?: string
   granularity?: Granularity
   hideTimeZone?: boolean = false
   hourCycle?: number | number
   id?: string
+  interactOutsideBehavior?: 'clear' | 'reset' | 'select' = 'select'
   isDateUnavailable?: (DateValue) => boolean
   isDisabled?: boolean
   isInvalid?: boolean
   isOpen?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxValue?: DateValue | null
   maxVisibleMonths?: number = 1
   minValue?: DateValue | null
   necessityIndicator?: NecessityIndicator = 'icon'
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (RangeValue<MappedDateValue<DateValue>> | null) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onOpenChange?: (boolean) => void
   pageBehavior?: PageBehavior = visible
   placeholderValue?: DateValue | null
   shouldCloseOnSelect?: boolean | () => boolean = true
   shouldFlip?: boolean = true
   shouldForceLeadingZeros?: boolean
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   startName?: string
   styles?: StylesProp
   validate?: (RangeValue<MappedDateValue<DateValue>>) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: RangeValue<DateValue> | null
 }

/@react-spectrum/s2:ListView

 ListView <T extends {}> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean | FocusStrategy
   children: ReactNode | ({}) => ReactNode
   defaultSelectedKeys?: 'all' | Iterable<Key>
   dependencies?: ReadonlyArray<any>
   disabledBehavior?: DisabledBehavior = "all"
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   disallowTypeAhead?: boolean = false
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   hideLinkOutIcon?: boolean
   id?: string
   isQuiet?: boolean
   items?: Iterable<T>
   loadingState?: LoadingState
   onAction?: (Key) => void
   onLoadMore?: () => void
   onSelectionChange?: (Selection) => void
+  orientation?: Orientation = 'vertical'
   overflowMode?: 'wrap' | 'truncate' = 'truncate'
   renderActionBar?: ('all' | Set<Key>) => ReactElement
   renderEmptyState?: (GridListRenderProps) => ReactNode
   selectedKeys?: 'all' | Iterable<Key>
   selectionStyle?: 'highlight' | 'checkbox' = 'checkbox'
   shouldSelectOnPressUp?: boolean
   slot?: string | null
   styles?: StylesPropWithHeight
 }

/@react-spectrum/s2:DateRangePickerProps

 DateRangePickerProps <T extends DateValue> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   allowsNonContiguousRanges?: boolean
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   createCalendar?: (CalendarIdentifier) => Calendar
   defaultOpen?: boolean
   defaultValue?: RangeValue<DateValue> | null
   description?: ReactNode
   endName?: string
   errorMessage?: ReactNode
   firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'
   form?: string
   granularity?: Granularity
   hideTimeZone?: boolean = false
   hourCycle?: number | number
   id?: string
+  interactOutsideBehavior?: 'clear' | 'reset' | 'select' = 'select'
   isDateUnavailable?: (DateValue) => boolean
   isDisabled?: boolean
   isInvalid?: boolean
   isOpen?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxValue?: DateValue | null
   maxVisibleMonths?: number = 1
   minValue?: DateValue | null
   necessityIndicator?: NecessityIndicator = 'icon'
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (RangeValue<MappedDateValue<DateValue>> | null) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onOpenChange?: (boolean) => void
   pageBehavior?: PageBehavior = visible
   placeholderValue?: DateValue | null
   shouldCloseOnSelect?: boolean | () => boolean = true
   shouldFlip?: boolean = true
   shouldForceLeadingZeros?: boolean
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   startName?: string
   styles?: StylesProp
   validate?: (RangeValue<MappedDateValue<DateValue>>) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: RangeValue<DateValue> | null
 }

/@react-spectrum/s2:ListViewProps

 ListViewProps <T> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean | FocusStrategy
   children: ReactNode | (T) => ReactNode
   defaultSelectedKeys?: 'all' | Iterable<Key>
   dependencies?: ReadonlyArray<any>
   disabledBehavior?: DisabledBehavior = "all"
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   disallowTypeAhead?: boolean = false
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   hideLinkOutIcon?: boolean
   id?: string
   isQuiet?: boolean
   items?: Iterable<T>
   loadingState?: LoadingState
   onAction?: (Key) => void
   onLoadMore?: () => void
   onSelectionChange?: (Selection) => void
+  orientation?: Orientation = 'vertical'
   overflowMode?: 'wrap' | 'truncate' = 'truncate'
   renderActionBar?: ('all' | Set<Key>) => ReactElement
   renderEmptyState?: (GridListRenderProps) => ReactNode
   selectedKeys?: 'all' | Iterable<Key>
   selectionStyle?: 'highlight' | 'checkbox' = 'checkbox'
   shouldSelectOnPressUp?: boolean
   slot?: string | null
   styles?: StylesPropWithHeight
 }

@react-stately/layout

/@react-stately/layout:TableLayout

 TableLayout <O extends TableLayoutProps = TableLayoutProps, T> {
-  constructor: (TableLayoutProps) => void
+  constructor: (ListLayoutOptions) => void
   getContentSize: () => Size
   getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget | null
   getDropTargetLayoutInfo: (ItemDropTarget) => LayoutInfo
   getLayoutInfo: (Key) => LayoutInfo | null
   shouldInvalidate: (Rect, Rect) => boolean
   shouldInvalidateLayoutOptions: (TableLayoutProps, TableLayoutProps) => boolean
   update: (InvalidationContext<TableLayoutProps>) => void
   updateItemSize: (Key, Size) => boolean
   virtualizer: Virtualizer<{}, any> | null
 }

/@react-stately/layout:ListLayoutOptions

 ListLayoutOptions {
   dropIndicatorThickness?: number = 2
-  estimatedHeadingSize?: number
-  estimatedRowSize?: number
+  estimatedHeadingHeight?: number
+  estimatedRowHeight?: number
   gap?: number = 0
-  headingSize?: number = 48
-  loaderSize?: number = 48
+  headingHeight?: number = 48
+  loaderHeight?: number = 48
   orientation?: Orientation = 'vertical'
   padding?: number = 0
-  rowSize?: number = 48
+  rowHeight?: number = 48
 }

/@react-stately/layout:TableLayoutProps

 TableLayoutProps {
   columnWidths?: Map<Key, number>
   dropIndicatorThickness?: number = 2
   estimatedHeadingHeight?: number
   estimatedRowHeight?: number
   gap?: number = 0
   headingHeight?: number = 48
   loaderHeight?: number = 48
+  orientation?: Orientation = 'vertical'
   padding?: number = 0
   rowHeight?: number = 48
 }

@LFDanLu LFDanLu added this pull request to the merge queue Mar 30, 2026
Merged via the queue into main with commit 352fa19 Mar 30, 2026
29 checks passed
@LFDanLu LFDanLu deleted the audit_stuff branch March 30, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation ready for review release S2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants