Skip to content

Commit dc9f7f4

Browse files
sayedrisatiamdarshshah
authored andcommitted
Scope container props to accessibility attributes
1 parent 0feacda commit dc9f7f4

3 files changed

Lines changed: 43 additions & 30 deletions

File tree

README.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -340,28 +340,28 @@ function PostList() {
340340

341341
## Props, `InfiniteScroll`
342342

343-
| Prop | Type | Required | Default | Description |
344-
| ---------------------------- | ------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
345-
| `dataLength` | `number` | yes | - | Current count of rendered items. The component resets its load guard each time this value changes, which allows `next()` to fire again on the next scroll. |
346-
| `next` | `() => void` | yes | - | Called once when the sentinel enters the viewport. Append new items to your list state inside this callback; do not replace the existing items. |
347-
| `hasMore` | `boolean` | yes | - | When `false`, the observer is disconnected and `next()` will not be called again. Set it to `false` when your data source has no more pages. |
348-
| `loader` | `ReactNode` | yes | - | Rendered below the list while the next page is loading. Displayed between the last item and the bottom sentinel. |
349-
| `endMessage` | `ReactNode` | no | - | Rendered below the list when `hasMore` is `false`. Use it for an "all caught up" or "no more items" message. |
350-
| `height` | `number \| string` | no | - | Creates a fixed-height scroll container wrapping the list. Accepts a pixel number or any CSS length string. Omit this prop to scroll the window instead. |
351-
| `scrollableTarget` | `HTMLElement \| string \| null` | no | - | The scrollable ancestor that already provides overflow scrollbars. Pass the element's `id` string or a direct `HTMLElement` reference. Required when the scroll container is neither the window nor the `height` wrapper. |
352-
| `scrollThreshold` | `number \| string` | no | `0.8` | How close to the bottom the user must scroll before `next()` is called. A fraction like `0.8` means 80% scrolled; a string like `"200px"` means within 200 px of the bottom edge. |
353-
| `inverse` | `boolean` | no | `false` | Reverse scroll direction for chat or messaging UIs. The sentinel moves to the top of the list. Use together with `flexDirection: column-reverse` on the scroll container. |
354-
| `pullDownToRefresh` | `boolean` | no | `false` | Enable pull-to-refresh gesture on touch and mouse. Requires `refreshFunction` to also be set. |
355-
| `refreshFunction` | `() => void` | no | - | Called once when the user pulls down past `pullDownToRefreshThreshold` pixels and releases. Only active when `pullDownToRefresh` is `true`. |
356-
| `pullDownToRefreshThreshold` | `number` | no | `100` | How many pixels the user must pull down before `refreshFunction` is triggered on release. |
357-
| `pullDownToRefreshContent` | `ReactNode` | no | - | Content shown inside the pull-to-refresh area while the user is pulling but has not yet reached the threshold. |
358-
| `releaseToRefreshContent` | `ReactNode` | no | - | Content shown inside the pull-to-refresh area once the threshold is passed and the user can release to trigger a refresh. |
359-
| `onScroll` | `(e: UIEvent) => void` | no | - | Callback fired on every scroll event on the container. Receives the native `UIEvent`. Useful for syncing UI state with scroll position. |
360-
| `className` | `string` | no | `''` | CSS class name applied to the inner scroll container div. |
361-
| `style` | `CSSProperties` | no | - | Inline style object applied to the inner scroll container div. Merged with the component's default layout styles. |
362-
| Any other div attribute | HTML div attributes | no | - | Additional attributes such as `role`, `aria-label`, and `tabIndex` are applied to the inner scroll container div. |
363-
| `hasChildren` | `boolean` | no | - | Set to `true` when `children` is a single element or a fragment rather than an array. Helps the component detect whether visible content exists to determine scroll state. |
364-
| `initialScrollY` | `number` | no | - | Scrolls the window to this Y offset on mount. Useful for restoring a user's scroll position when navigating back to a page. |
343+
| Prop | Type | Required | Default | Description |
344+
| ---------------------------- | ---------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
345+
| `dataLength` | `number` | yes | - | Current count of rendered items. The component resets its load guard each time this value changes, which allows `next()` to fire again on the next scroll. |
346+
| `next` | `() => void` | yes | - | Called once when the sentinel enters the viewport. Append new items to your list state inside this callback; do not replace the existing items. |
347+
| `hasMore` | `boolean` | yes | - | When `false`, the observer is disconnected and `next()` will not be called again. Set it to `false` when your data source has no more pages. |
348+
| `loader` | `ReactNode` | yes | - | Rendered below the list while the next page is loading. Displayed between the last item and the bottom sentinel. |
349+
| `endMessage` | `ReactNode` | no | - | Rendered below the list when `hasMore` is `false`. Use it for an "all caught up" or "no more items" message. |
350+
| `height` | `number \| string` | no | - | Creates a fixed-height scroll container wrapping the list. Accepts a pixel number or any CSS length string. Omit this prop to scroll the window instead. |
351+
| `scrollableTarget` | `HTMLElement \| string \| null` | no | - | The scrollable ancestor that already provides overflow scrollbars. Pass the element's `id` string or a direct `HTMLElement` reference. Required when the scroll container is neither the window nor the `height` wrapper. |
352+
| `scrollThreshold` | `number \| string` | no | `0.8` | How close to the bottom the user must scroll before `next()` is called. A fraction like `0.8` means 80% scrolled; a string like `"200px"` means within 200 px of the bottom edge. |
353+
| `inverse` | `boolean` | no | `false` | Reverse scroll direction for chat or messaging UIs. The sentinel moves to the top of the list. Use together with `flexDirection: column-reverse` on the scroll container. |
354+
| `pullDownToRefresh` | `boolean` | no | `false` | Enable pull-to-refresh gesture on touch and mouse. Requires `refreshFunction` to also be set. |
355+
| `refreshFunction` | `() => void` | no | - | Called once when the user pulls down past `pullDownToRefreshThreshold` pixels and releases. Only active when `pullDownToRefresh` is `true`. |
356+
| `pullDownToRefreshThreshold` | `number` | no | `100` | How many pixels the user must pull down before `refreshFunction` is triggered on release. |
357+
| `pullDownToRefreshContent` | `ReactNode` | no | - | Content shown inside the pull-to-refresh area while the user is pulling but has not yet reached the threshold. |
358+
| `releaseToRefreshContent` | `ReactNode` | no | - | Content shown inside the pull-to-refresh area once the threshold is passed and the user can release to trigger a refresh. |
359+
| `onScroll` | `(e: UIEvent) => void` | no | - | Callback fired on every scroll event on the container. Receives the native `UIEvent`. Useful for syncing UI state with scroll position. |
360+
| `className` | `string` | no | `''` | CSS class name applied to the inner scroll container div. |
361+
| `style` | `CSSProperties` | no | - | Inline style object applied to the inner scroll container div. Merged with the component's default layout styles. |
362+
| Accessibility attributes | `aria-*`, `role`, `tabIndex`, `id` | no | - | Accessibility attributes applied to the inner scroll container div for labelling, semantics, and keyboard focus management. |
363+
| `hasChildren` | `boolean` | no | - | Set to `true` when `children` is a single element or a fragment rather than an array. Helps the component detect whether visible content exists to determine scroll state. |
364+
| `initialScrollY` | `number` | no | - | Scrolls the window to this Y offset on mount. Useful for restoring a user's scroll position when navigating back to a page. |
365365

366366
## Props, `useInfiniteScroll`
367367

src/__tests__/index.test.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ describe('React Infinite Scroll Component', () => {
5252
loader={'Loading...'}
5353
hasMore={false}
5454
next={() => {}}
55+
id="loaded-items"
5556
role="list"
57+
tabIndex={0}
5658
aria-label="Loaded items"
5759
>
5860
<div />
@@ -62,7 +64,9 @@ describe('React Infinite Scroll Component', () => {
6264
const scrollContainer = container.querySelector(
6365
'.infinite-scroll-component'
6466
);
67+
expect(scrollContainer?.getAttribute('id')).toBe('loaded-items');
6568
expect(scrollContainer?.getAttribute('role')).toBe('list');
69+
expect(scrollContainer?.getAttribute('tabindex')).toBe('0');
6670
expect(scrollContainer?.getAttribute('aria-label')).toBe('Loaded items');
6771
});
6872

src/index.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
useCallback,
66
ReactNode,
77
CSSProperties,
8-
HTMLAttributes,
8+
AriaAttributes,
9+
AriaRole,
910
} from 'react';
1011
import { buildRootMargin } from './utils/buildRootMargin';
1112

@@ -17,11 +18,7 @@ export type {
1718

1819
type Fn = () => any;
1920

20-
export interface Props
21-
extends Omit<
22-
HTMLAttributes<HTMLDivElement>,
23-
'children' | 'style' | 'className' | 'onScroll'
24-
> {
21+
export interface Props extends AriaAttributes {
2522
/**
2623
* Total number of items currently rendered. Unlocks the next load when it
2724
* changes. Always pass the length of your full accumulated list, not just
@@ -122,6 +119,12 @@ export interface Props
122119
initialScrollY?: number;
123120
/** CSS class name added to the inner scroll container element. */
124121
className?: string;
122+
/** Accessibility role applied to the inner scroll container element. */
123+
role?: AriaRole;
124+
/** Tab order for keyboard focus management on the inner scroll container. */
125+
tabIndex?: number;
126+
/** DOM id for labelling or controlling the inner scroll container. */
127+
id?: string;
125128
}
126129

127130
export default function InfiniteScroll({
@@ -145,7 +148,10 @@ export default function InfiniteScroll({
145148
dataLength,
146149
initialScrollY,
147150
className = '',
148-
...containerProps
151+
role,
152+
tabIndex,
153+
id,
154+
...ariaProps
149155
}: Props) {
150156
const [showLoader, setShowLoader] = useState(false);
151157
const [pullToRefreshThresholdBreached, setPullToRefreshThresholdBreached] =
@@ -416,7 +422,10 @@ export default function InfiniteScroll({
416422
return (
417423
<div style={outerDivStyle} className="infinite-scroll-component__outerdiv">
418424
<div
419-
{...containerProps}
425+
{...ariaProps}
426+
role={role}
427+
tabIndex={tabIndex}
428+
id={id}
420429
className={['infinite-scroll-component', className]
421430
.filter(Boolean)
422431
.join(' ')}

0 commit comments

Comments
 (0)