Skip to content

Commit 9d8067c

Browse files
yihuiliaoLFDanLu
andauthored
RAC DropZone - fix aria violation + make aria-label more customizable (#4703)
* labeling ideas * allow custom aria-label * fix aria-label, add additional tests * add aria-label to useLabel --------- Co-authored-by: Daniel Lu <[email protected]>
1 parent 84a1f0f commit 9d8067c

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

packages/react-aria-components/src/DropZone.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212

1313
import {AriaLabelingProps} from '@react-types/shared';
1414
import {ContextValue, Provider, RenderProps, SlotProps, useContextProps, useRenderProps} from './utils';
15-
import {DropOptions, mergeProps, useClipboard, useDrop, useFocusRing, useHover, useId, VisuallyHidden} from 'react-aria';
15+
import {DropOptions, mergeProps, useClipboard, useDrop, useFocusRing, useHover, VisuallyHidden} from 'react-aria';
1616
import {FileTriggerContext} from './FileTrigger';
17-
import {filterDOMProps, useLabels} from '@react-aria/utils';
17+
import {filterDOMProps, useLabels, useSlotId} from '@react-aria/utils';
1818
import React, {createContext, ForwardedRef, forwardRef, useRef} from 'react';
1919
import {TextContext} from './Text';
2020

@@ -51,9 +51,10 @@ function DropZone(props: DropZoneProps, ref: ForwardedRef<HTMLDivElement>) {
5151
let {dropProps, dropButtonProps, isDropTarget} = useDrop({...props, ref: buttonRef, hasDropButton: true});
5252
let {hoverProps, isHovered} = useHover({});
5353
let {focusProps, isFocused, isFocusVisible} = useFocusRing();
54-
55-
let textId = useId();
56-
let labelProps = useLabels({'aria-labelledby': textId});
54+
55+
let textId = useSlotId();
56+
let ariaLabel = props['aria-label'] || 'DropZone';
57+
let labelProps = useLabels({'aria-label': ariaLabel, 'aria-labelledby': textId});
5758

5859
let {clipboardProps} = useClipboard({
5960
onPaste: (items) => props.onDrop?.({
@@ -92,8 +93,8 @@ function DropZone(props: DropZoneProps, ref: ForwardedRef<HTMLDivElement>) {
9293
<VisuallyHidden>
9394
<button
9495
{...mergeProps(dropButtonProps, focusProps, clipboardProps, labelProps)}
95-
aria-label="DropZone" // will need to update with string formatter
96-
ref={buttonRef} />
96+
aria-label={ariaLabel}
97+
ref={buttonRef} />
9798
</VisuallyHidden>
9899
{renderProps.children}
99100
</div>

packages/react-aria-components/stories/index.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ export const DropzoneExampleWithFileTriggerLink = (props) => (
797797
<div>
798798
<DropZone
799799
{...props}
800+
aria-label={'testing aria-label'}
800801
className={styles.dropzone}
801802
onDrop={action('OnDrop')}
802803
onDropEnter={action('OnDropEnter')}

packages/react-aria-components/test/DropZone.test.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import {act, fireEvent, render} from '@react-spectrum/test-utils';
14-
import {Button, DropZone, DropZoneContext, FileTrigger, Text} from '../';
14+
import {Button, DropZone, DropZoneContext, FileTrigger, Link, Text} from '../';
1515
import {ClipboardEvent, DataTransfer, DataTransferItem, DragEvent} from '@react-aria/dnd/test/mocks';
1616
import {Draggable} from '@react-aria/dnd/test/examples';
1717
import React from 'react';
@@ -112,7 +112,32 @@ describe('DropZone', () => {
112112
</DropZone>);
113113
let text = getByText('Test');
114114
let button = getByRole('button');
115-
expect(button).toHaveAttribute('aria-labelledby', `${text.id}`);
115+
expect(button).toHaveAttribute('aria-labelledby', `${button.id} ${text.id}`);
116+
});
117+
118+
it('should apply default aria-label', () => {
119+
let {getByRole} = render(
120+
<DropZone
121+
data-testid="foo">
122+
<FileTrigger>
123+
<Link>Upload</Link>
124+
</FileTrigger>
125+
</DropZone>);
126+
let button = getByRole('button');
127+
expect(button).toHaveAttribute('aria-label', 'DropZone');
128+
});
129+
130+
it('should allow custom aria-label', () => {
131+
let {getByRole} = render(
132+
<DropZone
133+
data-testid="foo"
134+
aria-label="test aria-label">
135+
<FileTrigger>
136+
<Link>Upload</Link>
137+
</FileTrigger>
138+
</DropZone>);
139+
let button = getByRole('button');
140+
expect(button).toHaveAttribute('aria-label', 'test aria-label');
116141
});
117142

118143
it('should support render props', () => {

0 commit comments

Comments
 (0)