Skip to content

Commit

Permalink
Group accessibility-related props of DndContext (#746)
Browse files Browse the repository at this point in the history
  • Loading branch information
clauderic authored May 19, 2022
1 parent 5f3c700 commit 4173087
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 30 deletions.
34 changes: 34 additions & 0 deletions .changeset/accessibility-related-props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
'@dnd-kit/core': major
---

#### Regrouping accessibility-related props

Accessibility-related props have been regrouped under the `accessibility` prop of `<DndContext>`:

```diff
<DndContext
- announcements={customAnnouncements}
- screenReaderInstructions={customScreenReaderInstructions}
+ accessibility={{
+ announcements: customAnnouncements,
+ screenReaderInstructions: customScreenReaderInstructions,
+ }}
```

This is a breaking change that will allow easier addition of new accessibility-related features without overloading the props namespace of `<DndContext>`.

#### Accessibility-related DOM nodes are no longer portaled by default

The DOM nodes for the screen reader instructions and announcements are no longer portaled into the `document.body` element by default.

This change is motivated by the fact that screen readers do not always announce ARIA live regions that are rendered on the `document.body`. Common examples of this include when rendering a `<DndContext>` within a `<dialog>` element or an element that has `role="dialog"`, only ARIA live regions rendered within the dialog will be announced.

Consumers can now opt to render announcements in the portal container of their choice using the `container` property of the `accessibility` prop:

```diff
<DndContext
+ accessibility={{
+ container: document.body,
+ }}
```
39 changes: 23 additions & 16 deletions packages/core/src/components/Accessibility/Accessibility.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@ import {HiddenText, LiveRegion, useAnnouncement} from '@dnd-kit/accessibility';

import type {Announcements, ScreenReaderInstructions} from './types';
import type {UniqueIdentifier} from '../../types';
import {defaultAnnouncements} from './defaults';
import {
defaultAnnouncements,
defaultScreenReaderInstructions,
} from './defaults';
import {DndMonitorArguments, useDndMonitor} from '../../hooks/monitor';

interface Props {
announcements?: Announcements;
screenReaderInstructions: ScreenReaderInstructions;
container?: Element;
screenReaderInstructions?: ScreenReaderInstructions;
hiddenTextDescribedById: UniqueIdentifier;
}

export function Accessibility({
announcements = defaultAnnouncements,
container,
hiddenTextDescribedById,
screenReaderInstructions,
screenReaderInstructions = defaultScreenReaderInstructions,
}: Props) {
const {announce, announcement} = useAnnouncement();
const liveRegionId = useUniqueId(`DndLiveRegion`);

const [mounted, setMounted] = useState(false);

useEffect(() => {
Expand Down Expand Up @@ -53,16 +57,19 @@ export function Accessibility({
)
);

return mounted
? createPortal(
<>
<HiddenText
id={hiddenTextDescribedById}
value={screenReaderInstructions.draggable}
/>
<LiveRegion id={liveRegionId} announcement={announcement} />
</>,
document.body
)
: null;
if (!mounted) {
return null;
}

const markup = (
<>
<HiddenText
id={hiddenTextDescribedById}
value={screenReaderInstructions.draggable}
/>
<LiveRegion id={liveRegionId} announcement={announcement} />
</>
);

return container ? createPortal(markup, container) : markup;
}
2 changes: 1 addition & 1 deletion packages/core/src/components/Accessibility/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {Announcements, ScreenReaderInstructions} from './types';

export const screenReaderInstructions: ScreenReaderInstructions = {
export const defaultScreenReaderInstructions: ScreenReaderInstructions = {
draggable: `
To pick up a draggable item, press the space bar.
While dragging, use the arrow keys to move the item.
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/components/Accessibility/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export {Accessibility} from './Accessibility';
export {defaultAnnouncements, screenReaderInstructions} from './defaults';
export {
defaultAnnouncements,
defaultScreenReaderInstructions,
} from './defaults';
export type {Announcements, ScreenReaderInstructions} from './types';
14 changes: 7 additions & 7 deletions packages/core/src/components/DndContext/DndContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ import type {
import {
Accessibility,
Announcements,
screenReaderInstructions as defaultScreenReaderInstructions,
ScreenReaderInstructions,
} from '../Accessibility';

Expand All @@ -87,14 +86,17 @@ import type {MeasuringConfiguration} from './types';

export interface Props {
id?: string;
accessibility?: {
announcements?: Announcements;
container?: Element;
screenReaderInstructions?: ScreenReaderInstructions;
};
autoScroll?: boolean | AutoScrollOptions;
announcements?: Announcements;
cancelDrop?: CancelDrop;
children?: React.ReactNode;
collisionDetection?: CollisionDetection;
measuring?: MeasuringConfiguration;
modifiers?: Modifiers;
screenReaderInstructions?: ScreenReaderInstructions;
sensors?: SensorDescriptor<any>[];
onDragStart?(event: DragStartEvent): void;
onDragMove?(event: DragMoveEvent): void;
Expand Down Expand Up @@ -129,14 +131,13 @@ enum Status {

export const DndContext = memo(function DndContext({
id,
accessibility,
autoScroll = true,
announcements,
children,
sensors = defaultSensors,
collisionDetection = rectIntersection,
measuring,
modifiers,
screenReaderInstructions = defaultScreenReaderInstructions,
...props
}: Props) {
const store = useReducer(reducer, undefined, getInitialState);
Expand Down Expand Up @@ -682,9 +683,8 @@ export const DndContext = memo(function DndContext({
</PublicContext.Provider>
</InternalContext.Provider>
<Accessibility
announcements={announcements}
{...accessibility}
hiddenTextDescribedById={draggableDescribedById}
screenReaderInstructions={screenReaderInstructions}
/>
</DndMonitorContext.Provider>
);
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export {defaultAnnouncements} from './Accessibility';
export {
defaultAnnouncements,
defaultScreenReaderInstructions,
} from './Accessibility';
export type {Announcements, ScreenReaderInstructions} from './Accessibility';
export {DndContext} from './DndContext';
export type {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
export {
DndContext,
DragOverlay,
DragOverlayProps,
defaultAnnouncements,
defaultScreenReaderInstructions,
defaultDropAnimation,
defaultDropAnimationSideEffects,
} from './components';
export type {
Announcements,
CancelDrop,
DndContextProps,
DragOverlayProps,
DropAnimation,
DropAnimationFunction,
DropAnimationFunctionArguments,
Expand Down
6 changes: 4 additions & 2 deletions stories/2 - Presets/Sortable/Sortable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ export function Sortable({

return (
<DndContext
announcements={announcements}
screenReaderInstructions={screenReaderInstructions}
accessibility={{
announcements,
screenReaderInstructions,
}}
sensors={sensors}
collisionDetection={collisionDetection}
onDragStart={({active}) => {
Expand Down
2 changes: 1 addition & 1 deletion stories/3 - Examples/Tree/SortableTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export function SortableTree({

return (
<DndContext
announcements={announcements}
accessibility={{announcements}}
sensors={sensors}
collisionDetection={closestCenter}
measuring={measuring}
Expand Down

0 comments on commit 4173087

Please sign in to comment.