From f61a61718559aaec053114a90d3256bcf5c64c27 Mon Sep 17 00:00:00 2001 From: Christofer Bodin Date: Thu, 12 Mar 2026 21:38:02 +0100 Subject: [PATCH 1/2] fix: Remove MacOS aria label workaround in listbox useOption (#9736) * Remove MacOS aria label workaround in listbox useOption * Add custom aria-label to one ListBoxItem in ListBox.stories --- packages/@react-aria/listbox/src/useOption.ts | 16 +++++----------- .../stories/ListBox.stories.tsx | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/@react-aria/listbox/src/useOption.ts b/packages/@react-aria/listbox/src/useOption.ts index a2856a8e9dd..f1e2628cee7 100644 --- a/packages/@react-aria/listbox/src/useOption.ts +++ b/packages/@react-aria/listbox/src/useOption.ts @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {chain, filterDOMProps, isMac, isWebKit, mergeProps, useLinkProps, useSlotId} from '@react-aria/utils'; +import {chain, filterDOMProps, mergeProps, useLinkProps, useSlotId} from '@react-aria/utils'; import {DOMAttributes, FocusableElement, Key, RefObject} from '@react-types/shared'; import {getItemCount} from '@react-stately/collections'; import {getItemId, listData} from './utils'; @@ -105,18 +105,12 @@ export function useOption(props: AriaOptionProps, state: ListState, ref: R let optionProps = { role: 'option', 'aria-disabled': isDisabled || undefined, - 'aria-selected': state.selectionManager.selectionMode !== 'none' ? isSelected : undefined + 'aria-selected': state.selectionManager.selectionMode !== 'none' ? isSelected : undefined, + 'aria-label': props['aria-label'], + 'aria-labelledby': labelId, + 'aria-describedby': descriptionId }; - // Safari with VoiceOver on macOS misreads options with aria-labelledby or aria-label as simply "text". - // We should not map slots to the label and description on Safari and instead just have VoiceOver read the textContent. - // https://bugs.webkit.org/show_bug.cgi?id=209279 - if (!(isMac() && isWebKit())) { - optionProps['aria-label'] = props['aria-label']; - optionProps['aria-labelledby'] = labelId; - optionProps['aria-describedby'] = descriptionId; - } - let item = state.collection.getItem(key); if (isVirtualized) { let index = Number(item?.index); diff --git a/packages/react-aria-components/stories/ListBox.stories.tsx b/packages/react-aria-components/stories/ListBox.stories.tsx index 0d24ae17d49..8566f284bdd 100644 --- a/packages/react-aria-components/stories/ListBox.stories.tsx +++ b/packages/react-aria-components/stories/ListBox.stories.tsx @@ -34,7 +34,7 @@ export const ListBoxExample: ListBoxStory = (args) => ( Foo Bar - Baz + Baz (Custom aria-label) Google ); From adcdec9f2ff1c4d15c5d6de68206974af091ceb1 Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Thu, 12 Mar 2026 18:18:18 -0500 Subject: [PATCH 2/2] fix: SSR hydration mismatch from Date.now private prop keys (#9787) --- packages/@react-aria/datepicker/src/useDateField.ts | 5 +++-- packages/@react-stately/form/src/useFormValidationState.ts | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/@react-aria/datepicker/src/useDateField.ts b/packages/@react-aria/datepicker/src/useDateField.ts index 5a04a465421..fe5c062ca13 100644 --- a/packages/@react-aria/datepicker/src/useDateField.ts +++ b/packages/@react-aria/datepicker/src/useDateField.ts @@ -55,8 +55,9 @@ export const hookData: WeakMap = new WeakMap = createContext({}); -export const privateValidationStateProp: string = '__formValidationState' + Date.now(); +// Private props that we pass from useFormValidationState to children. +// Ideally we'd use a Symbol for this, but React doesn't support them: https://github.com/facebook/react/issues/7552 +// This needs to be stable across server and client module evaluation for SSR hydration. +export const privateValidationStateProp: string = '__reactAriaFormValidationState'; interface FormValidationProps extends Validation { builtinValidation?: ValidationResult,