Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const defaultProps: DateRangePickerProps = {
granularity: 'day',
i18nStrings,
value: null,
ariaLabel: 'Date range picker',
placeholder: 'Test Placeholder',
onChange: () => {},
relativeOptions: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
38 changes: 37 additions & 1 deletion src/date-range-picker/__tests__/date-range-picker.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -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(
<FormField label="form-field-label">
<DateRangePicker {...currentModeDefaultProps} ariaLabel="aria-label" />
</FormField>
);
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(
<FormField label="form-field-label">
<div id="custom-arialabelledby">custom-aria-labelledby</div>
<DateRangePicker
{...currentModeDefaultProps}
ariaLabelledby="custom-arialabelledby"
ariaLabel="aria-label"
/>
</FormField>
);
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(
Expand Down
1 change: 0 additions & 1 deletion src/date-range-picker/__tests__/i18n-strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
17 changes: 15 additions & 2 deletions src/date-range-picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const DateRangePicker = React.forwardRef(
isValidRange = () => ({ valid: true }),
showClearButton = true,
dateOnly = false,
ariaLabel,
timeOffset,
getTimeOffset,
timeInputFormat = 'hh:mm:ss',
Expand Down Expand Up @@ -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<HTMLButtonElement | null>(null);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -354,6 +364,9 @@ const DateRangePicker = React.forwardRef(
</ResetContextsForModal>
}
/>
<div id={ariaLabelId} hidden={true}>
{ariaLabel || i18nStrings?.ariaLabel}
</div>
</div>
);
}
Expand Down
8 changes: 8 additions & 0 deletions src/date-range-picker/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down
3 changes: 0 additions & 3 deletions src/internal/components/button-trigger/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export interface ButtonTriggerProps extends BaseComponentProps {
inlineTokens?: boolean;
ariaHasPopup?: 'true' | 'listbox' | 'dialog';
ariaControls?: string;
ariaLabel?: string;
Copy link
Member Author

Choose a reason for hiding this comment

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

Not used anymore, since the select trigger also switched to the ariaLabelledby-only implementation.

ariaLabelledby?: string;
ariaDescribedby?: string;
onKeyDown?: CancelableEventHandler<BaseKeyDetail>;
Expand All @@ -53,7 +52,6 @@ const ButtonTrigger = (
inlineTokens,
inFilteringToken,
ariaHasPopup,
ariaLabel,
ariaLabelledby,
ariaDescribedby,
ariaControls,
Expand Down Expand Up @@ -90,7 +88,6 @@ const ButtonTrigger = (
),
disabled: disabled,
'aria-expanded': pressed,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
'aria-describedby': ariaDescribedby,
'aria-haspopup': ariaHasPopup ?? 'listbox',
Expand Down
Loading