A grid list displays a list of interactive items, with support for keyboard navigation, single or multiple selection, and row actions.
Vanilla CSS theme
--tint CSS variable used by the Vanilla CSS examples.Content
GridList follows the Collection Components API, accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the items prop, and a function to render the children.
import {GridList, GridListItem} from './GridList';
import {Text} from 'react-aria-components';
function Example() {
return (
<GridList
aria-label="Nature photos"
selectionMode="multiple"
layout="grid"
items={images}>
{(image) => (
<GridListItem textValue={image.title}>
<img src={image.image} width={image.width} height={image.height} alt="" />
<Text>{image.title}</Text>
<Text slot="description">By {image.user}</Text>
</GridListItem>
)}
</GridList>
);
}
Asynchronous loading
Use renderEmptyState to display a spinner during initial load. To enable infinite scrolling, render a <GridListLoadMoreItem> at the end of the list. Use whatever data fetching library you prefer – this example uses useAsyncList from react-stately.
import {GridList, GridListItem, GridListLoadMoreItem} from './GridList';
import {Collection, Text} from 'react-aria-components';
import {ProgressCircle} from './ProgressCircle';
import {useAsyncList} from '@react-stately/data';
type Item = {
id: string;
description?: string;
alt_description?: string;
urls: {regular: string};
width: number;
height: number;
user: {name: string};
};
function AsyncLoadingExample() {
let list = useAsyncList<Item, number | null>({
async load({signal, cursor, items}) {
let page = cursor || 1;
let res = await fetch(
`https://api.unsplash.com/topics/nature/photos?page=${page}&per_page=30&client_id=AJuU-FPh11hn7RuumUllp4ppT8kgiLS7LtOHp_sp4nc`,
{signal}
);
let nextItems = await res.json();
// Filter duplicates which might be returned by the API.
let existingKeys = new Set(items.map(i => i.id));
nextItems = nextItems.filter(i => !existingKeys.has(i.id) && (i.description || i.alt_description));
return {items: nextItems, cursor: nextItems.length ? page + 1 : null};
}
});
return (
<GridList
aria-label="Nature photos"
layout="grid"
selectionMode="multiple"
renderEmptyState={() => (
<ProgressCircle isIndeterminate aria-label="Loading..." />
)}>
<Collection items={list.items}>
{(item) => (
<GridListItem textValue={item.description || item.alt_description}>
<img src={item.urls.regular} width={item.width} height={item.height} alt="" />
<Text>{item.description || item.alt_description}</Text>
<Text slot="description">By {item.user.name}</Text>
</GridListItem>
)}
</Collection>
<GridListLoadMoreItem
onLoadMore={list.loadMore}
isLoading={list.loadingState === 'loadingMore'} />
</GridList>
);
}
Links
Use the href prop on a <GridListItem> to create a link. See the framework setup guide to learn how to integrate with your framework. Link interactions vary depending on the selection behavior. See the selection guide for more details.
Empty state
import {GridList} from './GridList';
<GridList
aria-label="Search results"
renderEmptyState={() => 'No results found.'}>
{[]}
</GridList>
Selection and actions
Use the selectionMode prop to enable single or multiple selection. The selected items can be controlled via the selectedKeys prop, matching the id prop of the items. The onAction event handles item actions. Items can be disabled with the isDisabled prop. See the selection guide for more details.
Current selection:
Drag and drop
GridList supports drag and drop interactions when the dragAndDropHooks prop is provided using the useDragAndDrop hook. Users can drop data on the list as a whole, on individual items, insert new items between existing ones, or reorder items. React Aria supports drag and drop via mouse, touch, keyboard, and screen reader interactions. See the drag and drop guide to learn more.
import {GridList, GridListItem} from './GridList';
import {useDragAndDrop, Text, useListData} from 'react-aria-components';
function Example() {
let list = useListData({
initialItems: images
});
let {dragAndDropHooks} = useDragAndDrop({
getItems: (keys, items: typeof list.items) => items.map(item => ({'text/plain': item.title})),
onReorder(e) {
if (e.target.dropPosition === 'before') {
list.moveBefore(e.target.key, e.keys);
} else if (e.target.dropPosition === 'after') {
list.moveAfter(e.target.key, e.keys);
}
}
});
return (
<GridList
aria-label="Reorderable list"
layout="grid"
selectionMode="multiple"
items={list.items}
dragAndDropHooks={dragAndDropHooks}
>
{image => (
<GridListItem textValue={image.title}>
<img src={image.image} width={image.width} height={image.height} alt="" />
<Text>{image.title}</Text>
<Text slot="description">{image.user}</Text>
</GridListItem>
)}
</GridList>
);
}
Examples
API
<GridList>
<GridListItem>
<Button slot="drag" />
<Checkbox slot="selection" /> or <SelectionIndicator />
</GridListItem>
<GridListLoadMoreItem />
</GridList>
GridList
A grid list displays a list of interactive items, with support for keyboard navigation, single or multiple selection, and row actions.
| Name | Type | Default |
|---|---|---|
disallowTypeAhead | boolean | Default: false
|
| Whether typeahead navigation is disabled. | ||
dragAndDropHooks | DragAndDropHooks | Default: — |
The drag and drop hooks returned by useDragAndDrop used to enable drag and drop behavior for the GridList. | ||
layout | 'stack' | 'grid' | Default: 'stack'
|
| Whether the items are arranged in a stack or grid. | ||
keyboardNavigationBehavior | 'arrow' | 'tab' | Default: 'arrow'
|
| Whether keyboard navigation to focusable elements within grid list items is via the left/right arrow keys or the tab key. | ||
children | ReactNode | | Default: — |
| The contents of the collection. | ||
items | Iterable | Default: — |
| Item objects in the collection. | ||
renderEmptyState | | Default: — |
| Provides content to display when there are no items in the list. | ||
dependencies | ReadonlyArray | Default: — |
| Values that should invalidate the item cache when using dynamic collections. | ||
selectionMode | SelectionMode | Default: — |
| The type of selection that is allowed in the collection. | ||
selectionBehavior | SelectionBehavior | Default: "toggle"
|
| How multiple selection should behave in the collection. | ||
selectedKeys | 'all' | Iterable | Default: — |
| The currently selected keys in the collection (controlled). | ||
defaultSelectedKeys | 'all' | Iterable | Default: — |
| The initial selected keys in the collection (uncontrolled). | ||
onSelectionChange | | Default: — |
| Handler that is called when the selection changes. | ||
disabledKeys | Iterable | Default: — |
| The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | ||
disabledBehavior | DisabledBehavior | Default: "all"
|
Whether disabledKeys applies to all interactions, or only selection. | ||
disallowEmptySelection | boolean | Default: — |
| Whether the collection allows empty selection. | ||
shouldSelectOnPressUp | boolean | Default: — |
| Whether selection should occur on press up instead of press down. | ||
escapeKeyBehavior | 'clearSelection' | 'none' | Default: 'clearSelection'
|
| Whether pressing the escape key should clear selection in the grid list or not. Most experiences should not modify this option as it eliminates a keyboard user's ability to easily clear selection. Only use if the escape key is being handled externally or should not trigger selection clearing contextually. | ||
Default className: react-aria-GridList
| Render Prop | CSS Selector |
|---|---|
isEmpty | CSS Selector: [data-empty]
|
| Whether the list has no items and should display its empty state. | |
isFocused | CSS Selector: [data-focused]
|
| Whether the grid list is currently focused. | |
isFocusVisible | CSS Selector: [data-focus-visible]
|
| Whether the grid list is currently keyboard focused. | |
isDropTarget | CSS Selector: [data-drop-target]
|
| Whether the grid list is currently the active drop target. | |
layout | CSS Selector: [data-layout="stack | grid"]
|
| Whether the items are arranged in a stack or grid. | |
state | CSS Selector: — |
| State of the grid list. | |
GridListItem
A GridListItem represents an individual item in a GridList.
| Name | Type | |
|---|---|---|
id | Key | |
| The unique id of the item. | ||
value | object | |
| The object value that this item represents. When using dynamic collections, this is set automatically. | ||
textValue | string | |
| A string representation of the item's contents, used for features like typeahead. | ||
isDisabled | boolean | |
| Whether the item is disabled. | ||
children | ChildrenOrFunction | |
| The children of the component. A function may be provided to alter the children based on component state. | ||
Default className: react-aria-GridListItem
| Render Prop | CSS Selector |
|---|---|
isHovered | CSS Selector: [data-hovered]
|
| Whether the item is currently hovered with a mouse. | |
isPressed | CSS Selector: [data-pressed]
|
| Whether the item is currently in a pressed state. | |
isSelected | CSS Selector: [data-selected]
|
| Whether the item is currently selected. | |
isFocused | CSS Selector: [data-focused]
|
| Whether the item is currently focused. | |
isFocusVisible | CSS Selector: [data-focus-visible]
|
| Whether the item is currently keyboard focused. | |
isDisabled | CSS Selector: [data-disabled]
|
Whether the item is non-interactive, i.e. both selection and actions are disabled and the item may
not be focused. Dependent on disabledKeys and disabledBehavior. | |
selectionMode | CSS Selector: [data-selection-mode="single | multiple"]
|
| The type of selection that is allowed in the collection. | |
selectionBehavior | CSS Selector: — |
| The selection behavior for the collection. | |
GridListLoadMoreItem
| Name | Type | Default |
|---|---|---|
children | ReactNode | Default: — |
| The load more spinner to render when loading additional items. | ||
isLoading | boolean | Default: — |
| Whether or not the loading spinner should be rendered or not. | ||
scrollOffset | number | Default: 1
|
| The amount of offset from the bottom of your scrollable region that should trigger load more. Uses a percentage value relative to the scroll body's client height. Load more is then triggered when your current scroll position's distance from the bottom of the currently loaded list of items is less than or equal to the provided value. (e.g. 1 = 100% of the scroll region's height). | ||
onLoadMore | | Default: — |
| Handler that is called when more items should be loaded, e.g. while scrolling near the bottom. | ||
Default className: react-aria-GridListLoadMoreItem