ListView

A ListView displays a list of interactive items, and allows a user to navigate, select, or perform an action.

selectionMode 
selectionStyle 
isQuiet 
import {ListView, ListViewItem, Text} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

<ListView
  aria-label="Files"
  selectionMode="multiple"
  styles={style({width: 'full', maxWidth: 400, height: 320})}>
  <ListViewItem id="adobe-photoshop" textValue="Adobe Photoshop">
    <Text>Adobe Photoshop</Text>
    <Text slot="description">Image editing software</Text>
  </ListViewItem>
  <ListViewItem id="adobe-xd" textValue="Adobe XD">
    <Text>Adobe XD</Text>
    <Text slot="description">UI/UX design tool</Text>
  </ListViewItem>
  <ListViewItem id="adobe-indesign" textValue="Adobe InDesign">
    <Text>Adobe InDesign</Text>
    <Text slot="description">Desktop publishing</Text>
  </ListViewItem>
</ListView>

Content

ListView 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 {ListView, ListViewItem} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

<ListView aria-label="Dynamic files" items={files} styles={style({width: 'full', maxWidth: 400, height: 320})}> {item => ( <ListViewItem id={item.id}>{item.name}</ListViewItem> )} </ListView>

Slots

ListViewItem supports icons, Text, Image, ActionMenu, and ActionButtonGroup as children, and must have a textValue prop for accessibility.

import {ActionButton, ActionButtonGroup, ActionMenu, Image, ListView, ListViewItem, MenuItem, Text} from '@react-spectrum/s2';
import Edit from '@react-spectrum/s2/icons/Edit';
import Copy from '@react-spectrum/s2/icons/Copy';
import Delete from '@react-spectrum/s2/icons/Delete';
import File from '@react-spectrum/s2/icons/File';
import Share from '@react-spectrum/s2/icons/Share';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

<div className={style({display: 'flex', gap: 24, width: 'full', flexWrap: 'wrap', justifyContent: 'center'})}> <ListView aria-label="Documents" items={documents} styles={style({flexGrow: 1, flexShrink: 1, flexBasis: 0, minWidth: 200, maxWidth: 400, height: 320})}>
{item => ( <ListViewItem id={item.id} textValue={item.name}> <File /> <Text>{item.name}</Text> <Text slot="description">Document</Text> <ActionButtonGroup aria-label="File actions"> <ActionButton aria-label="Edit"> <Edit /> </ActionButton> <ActionButton aria-label="Delete"> <Delete /> </ActionButton> </ActionButtonGroup> </ListViewItem> )} </ListView> <ListView aria-label="Images" items={images} styles={style({flexGrow: 1, flexShrink: 1, flexBasis: 0, minWidth: 200, maxWidth: 400, height: 320})}> {item => ( <ListViewItem id={item.id} textValue={item.name}> <Image src={item.image_url} alt={item.name} /> <Text>{item.name}</Text> <Text slot="description">Image</Text> <ActionMenu> <MenuItem> <Copy /> <Text>Copy</Text> </MenuItem> <MenuItem> <Share /> <Text>Share</Text> </MenuItem> <MenuItem> <Delete /> <Text>Delete</Text> </MenuItem> </ActionMenu> </ListViewItem> )} </ListView> </div>

Asynchronous loading

Use the loadingState and onLoadMore props to enable async loading and infinite scrolling.

import {ListView, ListViewItem} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {useAsyncList} from 'react-stately';

interface Character {
  name: string
}

function AsyncListView() {
  let list = useAsyncList<Character>({
    async load({signal, cursor}) {
      if (cursor) {
        cursor = cursor.replace(/^http:\/\//i, 'https://');
      }

      let res = await fetch(cursor || 'https://swapi.py4e.com/api/people/?search=', {signal});
      let json = await res.json();
      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <ListView
      aria-label="Star Wars characters"
      loadingState={list.loadingState}
      onLoadMore={list.loadMore}
      items={list.items}
      styles={style({width: 'full', maxWidth: 400, height: 320})}>
      {item => (
        <ListViewItem id={item.name}>{item.name}</ListViewItem>
      )}
    </ListView>
  );
}

Use the href prop on a ListViewItem to create a link. See the getting started guide to learn how to integrate with your framework. Link interactions vary depending on the selection behavior. See the selection guide for more details.

selectionMode 
isQuiet 
hideLinkOutIcon 
import {ListView, ListViewItem} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

<ListView aria-label="Bookmarks" styles={style({width: 'full', maxWidth: 400, height: 320})}>
  <ListViewItem id="adobe" href="https://adobe.com" target="_blank">
    adobe.com
  </ListViewItem>
  <ListViewItem id="spectrum" href="https://spectrum.adobe.com" target="_blank">
    spectrum.adobe.com
  </ListViewItem>
  <ListViewItem id="react-spectrum" href="https://react-spectrum.adobe.com" target="_blank">
    react-spectrum.adobe.com
  </ListViewItem>
</ListView>

Empty state

Use renderEmptyState to render placeholder content when there are no items.

No results

Press here for more info.
import {ListView, IllustratedMessage, Heading, Content, Link} from '@react-spectrum/s2';
import FolderOpen from '@react-spectrum/s2/illustrations/linear/FolderOpen';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

<ListView
  aria-label="Search results"
  styles={style({width: 'full', maxWidth: 400})}
  renderEmptyState={() => (
    <IllustratedMessage>
      <FolderOpen />
      <Heading>No results</Heading>
      <Content>Press <Link href="https://adobe.com">here</Link> for more info.</Content>
    </IllustratedMessage>
  )}>
  {[]}
</ListView>

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:

selectionMode 
selectionStyle 
isQuiet 
disabledBehavior 
disallowEmptySelection 
import {ListView, ListViewItem, ActionBar, ActionButton, type Selection} from '@react-spectrum/s2';
import Edit from '@react-spectrum/s2/icons/Edit';
import Copy from '@react-spectrum/s2/icons/Copy';
import Delete from '@react-spectrum/s2/icons/Delete';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {useState} from 'react';

function Example(props) {
  let [selected, setSelected] = useState<Selection>(new Set());

  return (
    <div className={style({width: 'full'})}>
      <ListView
        {...props}
        aria-label="Files"
        styles={style({width: 'full', maxWidth: 400, height: 320})}
        aria-label="Files"
        selectionMode="multiple"
        selectedKeys={selected}
        onSelectionChange={setSelected}
        onAction={key => alert(`Action on ${key}`)}
        renderActionBar={(selectedKeys) => {
          let selection = selectedKeys === 'all' ? 'all' : [...selectedKeys].join(', ');
          return (
            <ActionBar>
              <ActionButton aria-label="Edit" onPress={() => alert(`Edit ${selection}`)}>
                <Edit />
              </ActionButton>
              <ActionButton aria-label="Copy" onPress={() => alert(`Copy ${selection}`)}>
                <Copy />
              </ActionButton>
              <ActionButton aria-label="Delete" onPress={() => alert(`Delete ${selection}`)}>
                <Delete />
              </ActionButton>
            </ActionBar>
          );
        }}>
        <ListViewItem id="a">Brand guidelines.pdf</ListViewItem>
        <ListViewItem id="b">Icon set.svg</ListViewItem>
        <ListViewItem id="c">Homepage comp.fig</ListViewItem>
        <ListViewItem id="d" isDisabled>Archived.zip</ListViewItem>
      </ListView>
      <p>Current selection: {selected === 'all' ? 'all' : [...selected].join(', ')}</p>
    </div>
  );
}

Use the hasChildItems prop on ListViewItem to display a chevron indicator, signaling that an item can be navigated into. Combine with onAction and Breadcrumbs to build a drill-down navigation pattern.

    Root
  1. Root
import {Breadcrumbs, Breadcrumb, ListView, ListViewItem, Text} from '@react-spectrum/s2';
import App from '@react-spectrum/s2/icons/App';
import Folder from '@react-spectrum/s2/icons/Folder';
import File from '@react-spectrum/s2/icons/File';
import Image from '@react-spectrum/s2/icons/Image';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {Key} from 'react-aria';
import {useState} from 'react';

function NavigationExample() { let [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([ {id: 'root', name: 'Root', icon: <Folder />, children: rootItems} ]); let currentItems = breadcrumbs[breadcrumbs.length - 1].children; let onAction = (key: Key) => { let item = currentItems.find(item => item.id === key); if (item && 'children' in item) { setBreadcrumbs(prev => [...prev, item]); } }; let onBreadcrumbAction = (key: Key) => { let index = breadcrumbs.findIndex(item => item.id === key); setBreadcrumbs(breadcrumbs.slice(0, index + 1)); };
return ( <div className={style({display: 'flex', flexDirection: 'column', gap: 8, width: 'full', maxWidth: 400})}> <Breadcrumbs onAction={onBreadcrumbAction}> {breadcrumbs.map(item => ( <Breadcrumb key={item.id} id={item.id}>{item.name}</Breadcrumb> ))} </Breadcrumbs> <ListView aria-label={breadcrumbs[breadcrumbs.length - 1].name} items={currentItems} onAction={onAction} styles={style({width: 'full', height: 320})}> {item => ( <ListViewItem id={item.id} textValue={item.name} hasChildItems={item && 'children' in item}> {item.icon} <Text>{item.name}</Text> </ListViewItem> )} </ListView> </div> ); }

API

<ListView>
  <ListViewItem>
    <Icon />
    <Image />
    <Text />
    <Text slot="description" />
    <ActionMenu /> or <ActionButtonGroup />
  </ListViewItem>
</ListView>

ListView

NameTypeDefault
stylesDefault:

Spectrum-defined styles, returned by the style() macro.

renderActionBar(selectedKeys: 'all'Set<Key>) => ReactElementDefault:

Provides the ActionBar to display when items are selected in the ListView.

hideLinkOutIconbooleanDefault:

Hides the default link out icons on items that open links in a new tab.

disallowTypeAheadbooleanDefault: false

Whether typeahead navigation is disabled.

isQuietbooleanDefault:

Whether the ListView should be displayed with a quiet style.

selectionStyle'highlight''checkbox'Default: 'checkbox'

How selection should be displayed.

overflowMode'wrap''truncate'Default: 'truncate'

Sets the overflow behavior for item contents.

childrenReactNode(item: object) => ReactNodeDefault:

The children of the ListView.

itemsIterable<T>Default:

Item objects in the collection.

loadingStateDefault:

The current loading state of the ListView.

onLoadMore() => voidDefault:

Handler that is called when more items should be loaded, e.g. while scrolling near the bottom.

renderEmptyState(props: ) => ReactNodeDefault:

Provides content to display when there are no items in the list.

dependenciesReadonlyArray<any>Default:

Values that should invalidate the item cache when using dynamic collections.

selectionModeDefault:

The type of selection that is allowed in the collection.

selectedKeys'all'Iterable<Key>Default:

The currently selected keys in the collection (controlled).

defaultSelectedKeys'all'Iterable<Key>Default:

The initial selected keys in the collection (uncontrolled).

onSelectionChange(keys: ) => voidDefault:

Handler that is called when the selection changes.

disabledKeysIterable<Key>Default:

The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.

disabledBehaviorDefault: "all"

Whether disabledKeys applies to all interactions, or only selection.

disallowEmptySelectionbooleanDefault:

Whether the collection allows empty selection.

shouldSelectOnPressUpbooleanDefault:

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.

ListViewItem

NameType
childrenReactNode

The contents of the item.

hasChildItemsboolean

Whether the item has child items (renders a chevron indicator).

idKey

The unique id of the item.

valueT

The object value that this item represents. When using dynamic collections, this is set automatically.

textValuestring

A string representation of the item's contents, used for features like typeahead.

isDisabledboolean

Whether the item is disabled.