diff --git a/README.md b/README.md
index 584baba..4e40856 100644
--- a/README.md
+++ b/README.md
@@ -340,27 +340,28 @@ function PostList() {
## Props, `InfiniteScroll`
-| Prop | Type | Required | Default | Description |
-| ---------------------------- | ------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `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. |
-| `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. |
-| `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. |
-| `loader` | `ReactNode` | yes | - | Rendered below the list while the next page is loading. Displayed between the last item and the bottom sentinel. |
-| `endMessage` | `ReactNode` | no | - | Rendered below the list when `hasMore` is `false`. Use it for an "all caught up" or "no more items" message. |
-| `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. |
-| `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. |
-| `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. |
-| `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. |
-| `pullDownToRefresh` | `boolean` | no | `false` | Enable pull-to-refresh gesture on touch and mouse. Requires `refreshFunction` to also be set. |
-| `refreshFunction` | `() => void` | no | - | Called once when the user pulls down past `pullDownToRefreshThreshold` pixels and releases. Only active when `pullDownToRefresh` is `true`. |
-| `pullDownToRefreshThreshold` | `number` | no | `100` | How many pixels the user must pull down before `refreshFunction` is triggered on release. |
-| `pullDownToRefreshContent` | `ReactNode` | no | - | Content shown inside the pull-to-refresh area while the user is pulling but has not yet reached the threshold. |
-| `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. |
-| `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. |
-| `className` | `string` | no | `''` | CSS class name applied to the inner scroll container div. |
-| `style` | `CSSProperties` | no | - | Inline style object applied to the inner scroll container div. Merged with the component's default layout styles. |
-| `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. |
-| `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. |
+| Prop | Type | Required | Default | Description |
+| ---------------------------- | ---------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `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. |
+| `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. |
+| `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. |
+| `loader` | `ReactNode` | yes | - | Rendered below the list while the next page is loading. Displayed between the last item and the bottom sentinel. |
+| `endMessage` | `ReactNode` | no | - | Rendered below the list when `hasMore` is `false`. Use it for an "all caught up" or "no more items" message. |
+| `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. |
+| `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. |
+| `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. |
+| `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. |
+| `pullDownToRefresh` | `boolean` | no | `false` | Enable pull-to-refresh gesture on touch and mouse. Requires `refreshFunction` to also be set. |
+| `refreshFunction` | `() => void` | no | - | Called once when the user pulls down past `pullDownToRefreshThreshold` pixels and releases. Only active when `pullDownToRefresh` is `true`. |
+| `pullDownToRefreshThreshold` | `number` | no | `100` | How many pixels the user must pull down before `refreshFunction` is triggered on release. |
+| `pullDownToRefreshContent` | `ReactNode` | no | - | Content shown inside the pull-to-refresh area while the user is pulling but has not yet reached the threshold. |
+| `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. |
+| `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. |
+| `className` | `string` | no | `''` | CSS class name applied to the inner scroll container div. |
+| `style` | `CSSProperties` | no | - | Inline style object applied to the inner scroll container div. Merged with the component's default layout styles. |
+| Accessibility attributes | `aria-*`, `role`, `tabIndex`, `id` | no | - | Accessibility attributes applied to the inner scroll container div for labelling, semantics, and keyboard focus management. |
+| `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. |
+| `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. |
## Props, `useInfiniteScroll`
diff --git a/src/__tests__/index.test.tsx b/src/__tests__/index.test.tsx
index 99881cb..b07bf5d 100644
--- a/src/__tests__/index.test.tsx
+++ b/src/__tests__/index.test.tsx
@@ -45,6 +45,31 @@ describe('React Infinite Scroll Component', () => {
expect(container.querySelectorAll('.custom-class').length).toBe(1);
});
+ it('passes accessibility attributes to the scroll container', () => {
+ const { container } = render(
+ {}}
+ id="loaded-items"
+ role="list"
+ tabIndex={0}
+ aria-label="Loaded items"
+ >
+
+
+ );
+
+ const scrollContainer = container.querySelector(
+ '.infinite-scroll-component'
+ );
+ expect(scrollContainer?.getAttribute('id')).toBe('loaded-items');
+ expect(scrollContainer?.getAttribute('role')).toBe('list');
+ expect(scrollContainer?.getAttribute('tabindex')).toBe('0');
+ expect(scrollContainer?.getAttribute('aria-label')).toBe('Loaded items');
+ });
+
it('renders children when passed in', () => {
const { container } = render(
any;
-export interface Props {
+export interface Props extends AriaAttributes {
/**
* Total number of items currently rendered. Unlocks the next load when it
* changes. Always pass the length of your full accumulated list, not just
@@ -117,6 +119,12 @@ export interface Props {
initialScrollY?: number;
/** CSS class name added to the inner scroll container element. */
className?: string;
+ /** Accessibility role applied to the inner scroll container element. */
+ role?: AriaRole;
+ /** Tab order for keyboard focus management on the inner scroll container. */
+ tabIndex?: number;
+ /** DOM id for labelling or controlling the inner scroll container. */
+ id?: string;
}
export default function InfiniteScroll({
@@ -140,6 +148,10 @@ export default function InfiniteScroll({
dataLength,
initialScrollY,
className = '',
+ role,
+ tabIndex,
+ id,
+ ...ariaProps
}: Props) {
const [showLoader, setShowLoader] = useState(false);
const [pullToRefreshThresholdBreached, setPullToRefreshThresholdBreached] =
@@ -410,6 +422,10 @@ export default function InfiniteScroll({
return (