diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index b19b3647c2..b7c0e3b169 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -10800,6 +10800,12 @@ and set the property to a string of each ID separated by spaces (for example, \` "optional": true, "type": "string", }, + { + "description": "Adds \`aria-label\` to the trigger and dropdown.", + "name": "ariaLabel", + "optional": true, + "type": "string", + }, { "description": "Adds \`aria-labelledby\` to the component. If you're using this component within a form field, don't set this property because the form field component automatically sets it. diff --git a/src/date-range-picker/__tests__/date-range-picker-absolute.test.tsx b/src/date-range-picker/__tests__/date-range-picker-absolute.test.tsx index f6fd0fec3d..b2c7d562e3 100644 --- a/src/date-range-picker/__tests__/date-range-picker-absolute.test.tsx +++ b/src/date-range-picker/__tests__/date-range-picker-absolute.test.tsx @@ -17,6 +17,7 @@ const defaultProps: DateRangePickerProps = { granularity: 'day', i18nStrings, value: null, + ariaLabel: 'Date range picker', placeholder: 'Test Placeholder', onChange: () => {}, relativeOptions: [], diff --git a/src/date-range-picker/__tests__/date-range-picker-relative.test.tsx b/src/date-range-picker/__tests__/date-range-picker-relative.test.tsx index 7ed51d4208..628d1665fe 100644 --- a/src/date-range-picker/__tests__/date-range-picker-relative.test.tsx +++ b/src/date-range-picker/__tests__/date-range-picker-relative.test.tsx @@ -28,6 +28,7 @@ const defaultProps: DateRangePickerProps = { locale: 'en-US', i18nStrings, value: null, + ariaLabel: 'Date range picker', onChange: () => {}, relativeOptions: [ { key: 'previous-5-minutes', amount: 5, unit: 'minute', type: 'relative' }, diff --git a/src/date-range-picker/__tests__/date-range-picker.test.tsx b/src/date-range-picker/__tests__/date-range-picker.test.tsx index e1f2376c88..29d1518b8e 100644 --- a/src/date-range-picker/__tests__/date-range-picker.test.tsx +++ b/src/date-range-picker/__tests__/date-range-picker.test.tsx @@ -99,7 +99,16 @@ describe('Date range picker', () => { ); wrapper.openDropdown(); - expect(wrapper.findDropdown()!.getElement()).toHaveAttribute('aria-labelledby', '#element'); + expect(wrapper.findDropdown()!.getElement()).toHaveAttribute( + 'aria-labelledby', + expect.stringContaining('#element') + ); + }); + + test('aria-label', () => { + const { wrapper } = renderDateRangePicker({ ...currentModeDefaultProps, ariaLabel: 'Custom label' }); + const trigger = wrapper.findTrigger().getElement(); + expect(trigger).toHaveAccessibleName('Custom label'); }); test('aria-invalid', () => { @@ -112,6 +121,33 @@ describe('Date range picker', () => { expect(wrapper.findTrigger().getElement()).toHaveAttribute('id', 'test'); }); + test('appends ariaLabel to the form field label', () => { + const { container } = render( + + + + ); + const wrapper = createWrapper(container).findDateRangePicker()!; + const trigger = wrapper.findTrigger().getElement(); + expect(trigger).toHaveAccessibleName('form-field-label aria-label'); + }); + + test('appends ariaLabel to the ariaLabelledby prop', () => { + const { container } = render( + +
custom-aria-labelledby
+ +
+ ); + const wrapper = createWrapper(container).findDateRangePicker()!; + const trigger = wrapper.findTrigger().getElement(); + expect(trigger).toHaveAccessibleName('custom-aria-labelledby aria-label'); + }); + test('correctly labels the dropdown trigger with the selected value', () => { const value = { type: 'relative', amount: 5, unit: 'day' } as const; const { container } = render( diff --git a/src/date-range-picker/__tests__/i18n-strings.ts b/src/date-range-picker/__tests__/i18n-strings.ts index a6a2ec7c31..a6b3a873c3 100644 --- a/src/date-range-picker/__tests__/i18n-strings.ts +++ b/src/date-range-picker/__tests__/i18n-strings.ts @@ -3,7 +3,6 @@ import { DateRangePickerProps } from '../interfaces'; export const i18nStrings: DateRangePickerProps.I18nStrings = { - ariaLabel: 'date range picker', todayAriaLabel: 'TEST TODAY', currentMonthAriaLabel: 'TEST THIS MONTH', nextMonthAriaLabel: 'TEST NEXT MONTH', diff --git a/src/date-range-picker/index.tsx b/src/date-range-picker/index.tsx index eb369a8538..3611c166b2 100644 --- a/src/date-range-picker/index.tsx +++ b/src/date-range-picker/index.tsx @@ -104,6 +104,7 @@ const DateRangePicker = React.forwardRef( isValidRange = () => ({ valid: true }), showClearButton = true, dateOnly = false, + ariaLabel, timeOffset, getTimeOffset, timeInputFormat = 'hh:mm:ss', @@ -143,12 +144,22 @@ const DateRangePicker = React.forwardRef( ? { startDate: undefined, endDate: undefined } : normalizeTimeOffset(value, getTimeOffset, timeOffset); value = formatInitialValue(value, dateOnly, isMonthOnly, normalizedTimeOffset); + const baseProps = getBaseProps(rest); - const { invalid, warning, controlId, ariaDescribedby, ariaLabelledby } = useFormFieldContext({ + const ariaLabelId = useUniqueId('date-range-picker-arialabel-'); + const { + invalid, + warning, + controlId, + ariaDescribedby, + ariaLabelledby: contextAriaLabelledby, + } = useFormFieldContext({ ariaLabelledby: rest.ariaLabelledby ?? i18nStrings?.ariaLabelledby, ariaDescribedby: rest.ariaDescribedby ?? i18nStrings?.ariaDescribedby, ...rest, }); + const ariaLabelledby = joinStrings(contextAriaLabelledby, ariaLabelId); + const isSingleGrid = useMobile(); const triggerRef = useRef(null); @@ -275,7 +286,6 @@ const DateRangePicker = React.forwardRef( invalid={invalid} warning={warning} ariaLabelledby={joinStrings(ariaLabelledby, triggerContentId)} - ariaLabel={i18nStrings?.ariaLabel} ariaDescribedby={ariaDescribedby} className={clsx(testutilStyles.label, styles.label, { [styles['label-enabled']]: !readOnly && !disabled, @@ -354,6 +364,9 @@ const DateRangePicker = React.forwardRef( } /> + ); } diff --git a/src/date-range-picker/interfaces.ts b/src/date-range-picker/interfaces.ts index c9fc7334a1..3f3a505cf5 100644 --- a/src/date-range-picker/interfaces.ts +++ b/src/date-range-picker/interfaces.ts @@ -208,6 +208,11 @@ export interface DateRangePickerProps * Defaults to `false`. */ hideTimeOffset?: boolean; + + /** + * Adds `aria-label` to the trigger and dropdown. + */ + ariaLabel?: string; } export namespace DateRangePickerProps { @@ -310,16 +315,19 @@ export namespace DateRangePickerProps { export interface I18nStrings { /** * Adds `aria-label` to the trigger and dropdown. + * @deprecated Use `ariaLabel` on the component instead. */ ariaLabel?: string; /** * Adds `aria-labelledby` to the trigger and dropdown. + * @deprecated Use `ariaLabelledby` on the component instead. */ ariaLabelledby?: string; /** * Adds `aria-describedby` to the trigger and dropdown. + * @deprecated Use `ariaDescribedby` on the component instead. */ ariaDescribedby?: string; diff --git a/src/internal/components/button-trigger/index.tsx b/src/internal/components/button-trigger/index.tsx index 9d89d871a8..92ed21a2ed 100644 --- a/src/internal/components/button-trigger/index.tsx +++ b/src/internal/components/button-trigger/index.tsx @@ -28,7 +28,6 @@ export interface ButtonTriggerProps extends BaseComponentProps { inlineTokens?: boolean; ariaHasPopup?: 'true' | 'listbox' | 'dialog'; ariaControls?: string; - ariaLabel?: string; ariaLabelledby?: string; ariaDescribedby?: string; onKeyDown?: CancelableEventHandler; @@ -53,7 +52,6 @@ const ButtonTrigger = ( inlineTokens, inFilteringToken, ariaHasPopup, - ariaLabel, ariaLabelledby, ariaDescribedby, ariaControls, @@ -90,7 +88,6 @@ const ButtonTrigger = ( ), disabled: disabled, 'aria-expanded': pressed, - 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, 'aria-haspopup': ariaHasPopup ?? 'listbox',