ListView

ListView components render an accessible list of items that supports selection and virtualization.

Installyarn add @diallink-corp/convergo-react-list
Version4.1.2
Usageimport {ListView} from '@diallink-corp/convergo-react-list'

Static Collection

The ListView component can either render static or dynamic collections of data. For simple select components that need to render a list of pre-defined data a static collection should be used. Static collections cannot be changed over time.

<ListView aria-label='Static collection'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView aria-label='Static collection'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView aria-label="Static collection">
  <Item key="apples">
    Apples
  </Item>
  <Item key="bananas">
    Bananas
  </Item>
  <Item key="grapes">
    Grapes
  </Item>
  <Item key="oranges">
    Oranges
  </Item>
</ListView>

Static Collection With Sections

The ListView supports splitting its content into sections. Each section can have a title and a list of items..

<ListView aria-label='Static collection'>
  <Section key='tasty' title="Tasty">
    <Item key='bananas'>Bananas</Item>
    <Item key='oranges'>Oranges</Item>
  </Section>
  <Section key='neutral' title="Neutral">
    <Item key='apples'>Apples</Item>
    <Item key='grapes'>Grapes</Item>
  </Section>
</ListView>
<ListView aria-label='Static collection'>
  <Section key='tasty' title="Tasty">
    <Item key='bananas'>Bananas</Item>
    <Item key='oranges'>Oranges</Item>
  </Section>
  <Section key='neutral' title="Neutral">
    <Item key='apples'>Apples</Item>
    <Item key='grapes'>Grapes</Item>
  </Section>
</ListView>
<ListView aria-label="Static collection">
  <Section
    key="tasty"
    title="Tasty"
  >
    <Item key="bananas">
      Bananas
    </Item>
    <Item key="oranges">
      Oranges
    </Item>
  </Section>
  <Section
    key="neutral"
    title="Neutral"
  >
    <Item key="apples">
      Apples
    </Item>
    <Item key="grapes">
      Grapes
    </Item>
  </Section>
</ListView>

Dynamic Collection

For data that is non-static, such as data fetched from a backend, the ListView component supports dynamic collections. Dynamic collections support adding, updating and removing of the data that is being rendered.

function Example() {
  const [fruits, setFruits] = useState([
    {id: 1, name: 'Apples'},
    {id: 2, name: 'Bananas'},
    {id: 3, name: 'Grapes'},
    {id: 4, name: 'Oranges'}
  ]);

  return (
    <ListView aria-label='Fruits' items={fruits}>
      {(item) => <Item key={item.id}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const [fruits, setFruits] = useState([
    {id: 1, name: 'Apples'},
    {id: 2, name: 'Bananas'},
    {id: 3, name: 'Grapes'},
    {id: 4, name: 'Oranges'}
  ]);

  return (
    <ListView aria-label='Fruits' items={fruits}>
      {(item) => <Item key={item.id}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const [
    fruits,
    setFruits
  ] = useState([
    {
      id: 1,
      name: 'Apples'
    },
    {
      id: 2,
      name: 'Bananas'
    },
    {
      id: 3,
      name: 'Grapes'
    },
    {
      id: 4,
      name: 'Oranges'
    }
  ]);

  return (
    <ListView
      aria-label="Fruits"
      items={fruits}
    >
      {(item) => (
        <Item
          key={item.id}
        >
          {item.name}
        </Item>
      )}
    </ListView>
  );
}

Asynchronous Fetching

The Select component supports asynchronous fetching of data via the onLoadMoreItems prop. The select component uses its built-in infinite scrolling to achieve this. This means that when the user reaches the bottom of the list, the component will automatically load more data. If you provide an loadingState prop, the Select component will show a Spinner component, to indicate to the user, that more data is being fetched.

function Example() {
  const [reversed, setReversed] = useState(false);

  const limit = 20;

  const list = useAsyncListState({
    async loadItems(state) {
      const { cursor, signal } = state;
      const response = await fetch(
        cursor || `https://pokeapi.co/api/v2/pokemon?limit=${limit}`,
        { signal }
      );
      const result = await response.json();
      const { results, next } = result;
      return { items: results, cursor: next };
    },
    initialItems: []
  });

  const items = {
    *[Symbol.iterator]() {
      let page = 1;
      let section = { key: page, items: [] };
      for (let item of list.items) {
        if (section.items.length < limit) {
          section.items.push(item);
        } else {
          yield section;

          page += 1;
          section = { key: page, items: [item] };
        }
      }

      if (section.items.length > 0) {
        yield section;
      }
    }
  };

  return (
    <>
      <Switch
        label="Reverse"
        defaultSelected={reversed}
        onChange={setReversed}
      />
      <ListView
        key={reversed}
        aria-label="Pokemons"
        items={items}
        loadingState={list.loadingState}
        onLoadMoreItems={list.loadMoreItems}
        defaultSelectedKey="vileplume"
        style={{ maxHeight: '300px' }}
        reverse={reversed}
        style={{ maxHeight: '300px' }}
      >
        {(section) => (
          <Section
            key={section.key}
            title={'Page ' + section.key}
            items={section.items}
          >
            {(item) => <Item key={item.name}>{item.name}</Item>}
          </Section>
        )}
      </ListView>
    </>
  );
}
function Example() {
  const [reversed, setReversed] = useState(false);

  const limit = 20;

  const list = useAsyncListState({
    async loadItems(state) {
      const { cursor, signal } = state;
      const response = await fetch(
        cursor ||
          `https://pokeapi.co/api/v2/pokemon?limit=${limit}`,
        { signal }
      );
      const result = await response.json();
      const { results, next } = result;
      return { items: results, cursor: next };
    },
    initialItems: []
  });

  const items = {
    *[Symbol.iterator]() {
      let page = 1;
      let section = { key: page, items: [] };
      for (let item of list.items) {
        if (section.items.length < limit) {
          section.items.push(item);
        } else {
          yield section;

          page += 1;
          section = { key: page, items: [item] };
        }
      }

      if (section.items.length > 0) {
        yield section;
      }
    }
  };

  return (
    <>
      <Switch
        label="Reverse"
        defaultSelected={reversed}
        onChange={setReversed}
      />
      <ListView
        key={reversed}
        aria-label="Pokemons"
        items={items}
        loadingState={list.loadingState}
        onLoadMoreItems={list.loadMoreItems}
        defaultSelectedKey="vileplume"
        style={{ maxHeight: '300px' }}
        reverse={reversed}
        style={{ maxHeight: '300px' }}
      >
        {(section) => (
          <Section
            key={section.key}
            title={'Page ' + section.key}
            items={section.items}
          >
            {(item) => (
              <Item key={item.name}>{item.name}</Item>
            )}
          </Section>
        )}
      </ListView>
    </>
  );
}
function Example() {
  const [
    reversed,
    setReversed
  ] = useState(false);

  const limit = 20;

  const list =
    useAsyncListState({
      async loadItems(
        state
      ) {
        const {
          cursor,
          signal
        } = state;
        const response =
          await fetch(
            cursor ||
              `https://pokeapi.co/api/v2/pokemon?limit=${limit}`,
            { signal }
          );
        const result =
          await response
            .json();
        const {
          results,
          next
        } = result;
        return {
          items: results,
          cursor: next
        };
      },
      initialItems: []
    });

  const items = {
    *[
      Symbol.iterator
    ]() {
      let page = 1;
      let section = {
        key: page,
        items: []
      };
      for (
        let item of list
          .items
      ) {
        if (
          section.items
            .length <
            limit
        ) {
          section.items
            .push(item);
        } else {
          yield section;

          page += 1;
          section = {
            key: page,
            items: [
              item
            ]
          };
        }
      }

      if (
        section.items
          .length > 0
      ) {
        yield section;
      }
    }
  };

  return (
    <>
      <Switch
        label="Reverse"
        defaultSelected={reversed}
        onChange={setReversed}
      />
      <ListView
        key={reversed}
        aria-label="Pokemons"
        items={items}
        loadingState={list
          .loadingState}
        onLoadMoreItems={list
          .loadMoreItems}
        defaultSelectedKey="vileplume"
        style={{
          maxHeight:
            '300px'
        }}
        reverse={reversed}
        style={{
          maxHeight:
            '300px'
        }}
      >
        {(section) => (
          <Section
            key={section
              .key}
            title={'Page ' +
              section
                .key}
            items={section
              .items}
          >
            {(item) => (
              <Item
                key={item
                  .name}
              >
                {item
                  .name}
              </Item>
            )}
          </Section>
        )}
      </ListView>
    </>
  );
}

Uncontrolled Selection

By default, the ListView component handles its selection uncontrolled. In the uncontrolled variant you can pass in a defaultSelectedKeys to select one or more values by default. The key that is being referenced here is the value that is passed to the Item component as a key prop, so in this case item.name.

function Example() {
  const fruits = [
    { id: 1, name: 'Apples' },
    { id: 2, name: 'Bananas' },
    { id: 3, name: 'Grapes' },
    { id: 4, name: 'Oranges' }
  ];

  return (
    <ListView
      aria-label="Fruits"
      items={fruits}
      defaultSelectedKeys={['Grapes']}
      selectionMode="single"
    >
      {(item) => <Item key={item.name}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const fruits = [
    { id: 1, name: 'Apples' },
    { id: 2, name: 'Bananas' },
    { id: 3, name: 'Grapes' },
    { id: 4, name: 'Oranges' }
  ];

  return (
    <ListView
      aria-label="Fruits"
      items={fruits}
      defaultSelectedKeys={['Grapes']}
      selectionMode="single"
    >
      {(item) => <Item key={item.name}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const fruits = [
    {
      id: 1,
      name: 'Apples'
    },
    {
      id: 2,
      name: 'Bananas'
    },
    {
      id: 3,
      name: 'Grapes'
    },
    {
      id: 4,
      name: 'Oranges'
    }
  ];

  return (
    <ListView
      aria-label="Fruits"
      items={fruits}
      defaultSelectedKeys={[
        'Grapes'
      ]}
      selectionMode="single"
    >
      {(item) => (
        <Item
          key={item.name}
        >
          {item.name}
        </Item>
      )}
    </ListView>
  );
}

Controlled Selection

The use the controlled selection variant, you can use the selectedKey and onSelectionChange props together.

function Example() {
  const fruits = [
    { id: '1', name: 'Apples' },
    { id: '2', name: 'Bananas' },
    { id: '3', name: 'Grapes' },
    { id: '4', name: 'Oranges' }
  ];
  const [selectedFruit, setSelectedFruit] = useState('2');

  return (
    <ListView
      aria-label="What is your favorite fruit?"
      items={fruits}
      selectionMode="single"
      selectedKeys={[selectedFruit]}
      onSelectionChange={(value) =>
        setSelectedFruit(value.values().next().value)}
    >
      {(item) => <Item key={item.id}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const fruits = [
    { id: '1', name: 'Apples' },
    { id: '2', name: 'Bananas' },
    { id: '3', name: 'Grapes' },
    { id: '4', name: 'Oranges' }
  ];
  const [selectedFruit, setSelectedFruit] = useState('2');

  return (
    <ListView
      aria-label="What is your favorite fruit?"
      items={fruits}
      selectionMode="single"
      selectedKeys={[selectedFruit]}
      onSelectionChange={(value) =>
        setSelectedFruit(value.values().next().value)}
    >
      {(item) => <Item key={item.id}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const fruits = [
    {
      id: '1',
      name: 'Apples'
    },
    {
      id: '2',
      name: 'Bananas'
    },
    {
      id: '3',
      name: 'Grapes'
    },
    {
      id: '4',
      name: 'Oranges'
    }
  ];
  const [
    selectedFruit,
    setSelectedFruit
  ] = useState('2');

  return (
    <ListView
      aria-label="What is your favorite fruit?"
      items={fruits}
      selectionMode="single"
      selectedKeys={[
        selectedFruit
      ]}
      onSelectionChange={(
        value
      ) =>
        setSelectedFruit(
          value.values()
            .next().value
        )}
    >
      {(item) => (
        <Item
          key={item.id}
        >
          {item.name}
        </Item>
      )}
    </ListView>
  );
}

Density

The ListView supports various densities to control the size of the items.

Compact

<ListView aria-label='Compact list'  density='compact'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView aria-label='Compact list'  density='compact'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView
  aria-label="Compact list"
  density="compact"
>
  <Item key="apples">
    Apples
  </Item>
  <Item key="bananas">
    Bananas
  </Item>
  <Item key="grapes">
    Grapes
  </Item>
  <Item key="oranges">
    Oranges
  </Item>
</ListView>

Regular

<ListView aria-label='Regular list'  density='regular'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView aria-label='Regular list'  density='regular'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView
  aria-label="Regular list"
  density="regular"
>
  <Item key="apples">
    Apples
  </Item>
  <Item key="bananas">
    Bananas
  </Item>
  <Item key="grapes">
    Grapes
  </Item>
  <Item key="oranges">
    Oranges
  </Item>
</ListView>

Spacious

<ListView aria-label='Spacious list' density='spacious'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView aria-label='Spacious list' density='spacious'>
  <Item key='apples'>Apples</Item>
  <Item key='bananas'>Bananas</Item>
  <Item key='grapes'>Grapes</Item>
  <Item key='oranges'>Oranges</Item>
</ListView>
<ListView
  aria-label="Spacious list"
  density="spacious"
>
  <Item key="apples">
    Apples
  </Item>
  <Item key="bananas">
    Bananas
  </Item>
  <Item key="grapes">
    Grapes
  </Item>
  <Item key="oranges">
    Oranges
  </Item>
</ListView>

Drag & Drop

The ListView component supports drag & drop out of the box.

function Example(props) {
  const items = [
    { key: 'a', name: 'A', type: 'file' },
    { key: 'b', name: 'B', type: 'file' },
    { key: 'c', name: 'C', type: 'folder' },
    { key: 'd', name: 'D', type: 'file' },
    { key: 'e', name: 'E', type: 'folder' },
    { key: 'f', name: 'F', type: 'file' },
    { key: 'g', name: 'G', type: 'file' },
    { key: 'h', name: 'H', type: 'file' },
    { key: 'i', name: 'I', type: 'file' },
    { key: 'j', name: 'J', type: 'file' },
    { key: 'k', name: 'K', type: 'file' },
    { key: 'l', name: 'L', type: 'file' },
    { key: 'm', name: 'M', type: 'folder' },
    { key: 'n', name: 'N', type: 'file' }
  ];

  const getItems = (keys) =>
    [...keys].map((key) => {
      const item = items.find((item) => item.key === key);
      return {
        'text/plain': item.name
      };
    });

  const allowsDraggingItem = (key) => {
    const item = items.find((item) => item.key === key);
    return item.type !== 'folder';
  };

  const { dragHooks } = useDragAndDrop({
    allowsDraggingItem,
    getItems
  });

  return (
    <ListView
      aria-label="Draggable list view"
      stlye={{ width: '300px' }}
      selectionMode="multiple"
      items={items}
      disabledKeys={['f']}
      dragHooks={dragHooks}
    >
      {(item) => (
        <Item key={item.key} textValue={item.name}>
          {item.type === 'folder' && (
            <Icon name="FolderIcon" variant="outline" />
          )}
          {item.key === 'a' && <Icon name="DocumentIcon" variant="outline" />}
          <Content>{item.name}</Content>
          {item.key === 'b' && <Description>Beta</Description>}
          <ActionMenu>
            <Item key="edit" textValue="Edit">
              <Icon name="PencilIcon" variant="outline" />
              <Text>Edit</Text>
            </Item>
            <Item key="delete" textValue="Delete">
              <Icon name="XMarkIcon" variant="outline" />
              <Text>Delete</Text>
            </Item>
          </ActionMenu>
        </Item>
      )}
    </ListView>
  );
}
function Example(props) {
  const items = [
    { key: 'a', name: 'A', type: 'file' },
    { key: 'b', name: 'B', type: 'file' },
    { key: 'c', name: 'C', type: 'folder' },
    { key: 'd', name: 'D', type: 'file' },
    { key: 'e', name: 'E', type: 'folder' },
    { key: 'f', name: 'F', type: 'file' },
    { key: 'g', name: 'G', type: 'file' },
    { key: 'h', name: 'H', type: 'file' },
    { key: 'i', name: 'I', type: 'file' },
    { key: 'j', name: 'J', type: 'file' },
    { key: 'k', name: 'K', type: 'file' },
    { key: 'l', name: 'L', type: 'file' },
    { key: 'm', name: 'M', type: 'folder' },
    { key: 'n', name: 'N', type: 'file' }
  ];

  const getItems = (keys) =>
    [...keys].map((key) => {
      const item = items.find((item) => item.key === key);
      return {
        'text/plain': item.name
      };
    });

  const allowsDraggingItem = (key) => {
    const item = items.find((item) => item.key === key);
    return item.type !== 'folder';
  };

  const { dragHooks } = useDragAndDrop({
    allowsDraggingItem,
    getItems
  });

  return (
    <ListView
      aria-label="Draggable list view"
      stlye={{ width: '300px' }}
      selectionMode="multiple"
      items={items}
      disabledKeys={['f']}
      dragHooks={dragHooks}
    >
      {(item) => (
        <Item key={item.key} textValue={item.name}>
          {item.type === 'folder' && (
            <Icon name="FolderIcon" variant="outline" />
          )}
          {item.key === 'a' && (
            <Icon name="DocumentIcon" variant="outline" />
          )}
          <Content>{item.name}</Content>
          {item.key === 'b' && (
            <Description>Beta</Description>
          )}
          <ActionMenu>
            <Item key="edit" textValue="Edit">
              <Icon name="PencilIcon" variant="outline" />
              <Text>Edit</Text>
            </Item>
            <Item key="delete" textValue="Delete">
              <Icon name="XMarkIcon" variant="outline" />
              <Text>Delete</Text>
            </Item>
          </ActionMenu>
        </Item>
      )}
    </ListView>
  );
}
function Example(props) {
  const items = [
    {
      key: 'a',
      name: 'A',
      type: 'file'
    },
    {
      key: 'b',
      name: 'B',
      type: 'file'
    },
    {
      key: 'c',
      name: 'C',
      type: 'folder'
    },
    {
      key: 'd',
      name: 'D',
      type: 'file'
    },
    {
      key: 'e',
      name: 'E',
      type: 'folder'
    },
    {
      key: 'f',
      name: 'F',
      type: 'file'
    },
    {
      key: 'g',
      name: 'G',
      type: 'file'
    },
    {
      key: 'h',
      name: 'H',
      type: 'file'
    },
    {
      key: 'i',
      name: 'I',
      type: 'file'
    },
    {
      key: 'j',
      name: 'J',
      type: 'file'
    },
    {
      key: 'k',
      name: 'K',
      type: 'file'
    },
    {
      key: 'l',
      name: 'L',
      type: 'file'
    },
    {
      key: 'm',
      name: 'M',
      type: 'folder'
    },
    {
      key: 'n',
      name: 'N',
      type: 'file'
    }
  ];

  const getItems = (
    keys
  ) =>
    [...keys].map(
      (key) => {
        const item =
          items.find((
            item
          ) =>
            item.key ===
              key
          );
        return {
          'text/plain':
            item.name
        };
      }
    );

  const allowsDraggingItem =
    (key) => {
      const item = items
        .find((item) =>
          item.key ===
            key
        );
      return item
        .type !==
        'folder';
    };

  const { dragHooks } =
    useDragAndDrop({
      allowsDraggingItem,
      getItems
    });

  return (
    <ListView
      aria-label="Draggable list view"
      stlye={{
        width: '300px'
      }}
      selectionMode="multiple"
      items={items}
      disabledKeys={[
        'f'
      ]}
      dragHooks={dragHooks}
    >
      {(item) => (
        <Item
          key={item.key}
          textValue={item
            .name}
        >
          {item.type ===
              'folder' &&
            (
              <Icon
                name="FolderIcon"
                variant="outline"
              />
            )}
          {item.key ===
              'a' && (
            <Icon
              name="DocumentIcon"
              variant="outline"
            />
          )}
          <Content>
            {item.name}
          </Content>
          {item.key ===
              'b' && (
            <Description>
              Beta
            </Description>
          )}
          <ActionMenu>
            <Item
              key="edit"
              textValue="Edit"
            >
              <Icon
                name="PencilIcon"
                variant="outline"
              />
              <Text>
                Edit
              </Text>
            </Item>
            <Item
              key="delete"
              textValue="Delete"
            >
              <Icon
                name="XMarkIcon"
                variant="outline"
              />
              <Text>
                Delete
              </Text>
            </Item>
          </ActionMenu>
        </Item>
      )}
    </ListView>
  );
}

Overflow Mode

By default, the text of the ListView is truncated if it overflows. By setting the overflowMode prop to 'wrap', you can wrap the text instead.

<ListView
  aria-label="Overflow truncate"
  overflowMode="truncate"
  style={{ width: '300px' }}
>
  <Item key="a">
    A really really really really really really really really long description
    to test
  </Item>
  <Item key="b">
    A really really really really really really really really long description
    to test
  </Item>
  <Item key="c">
    A really really really really really really really really long description
    to test
  </Item>
  <Item key="d">
    A really really really really really really really really long description
    to test
  </Item>
</ListView>
<ListView
  aria-label="Overflow truncate"
  overflowMode="truncate"
  style={{ width: '300px' }}
>
  <Item key="a">
    A really really really really really really really
    really long description to test
  </Item>
  <Item key="b">
    A really really really really really really really
    really long description to test
  </Item>
  <Item key="c">
    A really really really really really really really
    really long description to test
  </Item>
  <Item key="d">
    A really really really really really really really
    really long description to test
  </Item>
</ListView>
<ListView
  aria-label="Overflow truncate"
  overflowMode="truncate"
  style={{
    width: '300px'
  }}
>
  <Item key="a">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
  <Item key="b">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
  <Item key="c">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
  <Item key="d">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
</ListView>
<ListView
  aria-label="Overflow wrap"
  overflowMode="wrap"
  style={{ width: '300px' }}
>
  <Item key="a">
    A really really really really really really really really long description
    to test
  </Item>
  <Item key="b">
    A really really really really really really really really long description
    to test
  </Item>
  <Item key="c">
    A really really really really really really really really long description
    to test
  </Item>
  <Item key="d">
    A really really really really really really really really long description
    to test
  </Item>
</ListView>
<ListView
  aria-label="Overflow wrap"
  overflowMode="wrap"
  style={{ width: '300px' }}
>
  <Item key="a">
    A really really really really really really really
    really long description to test
  </Item>
  <Item key="b">
    A really really really really really really really
    really long description to test
  </Item>
  <Item key="c">
    A really really really really really really really
    really long description to test
  </Item>
  <Item key="d">
    A really really really really really really really
    really long description to test
  </Item>
</ListView>
<ListView
  aria-label="Overflow wrap"
  overflowMode="wrap"
  style={{
    width: '300px'
  }}
>
  <Item key="a">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
  <Item key="b">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
  <Item key="c">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
  <Item key="d">
    A really really
    really really
    really really
    really really long
    description to test
  </Item>
</ListView>

Slots

The ListView comes with several pre-defined slots to define styles of its children.

function Example() {
  const [fruits, setFruits] = useState([
    {id: 1, name: 'Apples', description: 'Sweet-tart'},
    {id: 2, name: 'Bananas', description: 'Fruity'},
    {id: 3, name: 'Grapes', description: 'Sweet-sour'},
    {id: 4, name: 'Oranges', description: 'Sweet-tart'},
  ]);

  return (
    <ListView aria-label='Fruits' items={fruits}>
      {(item) => (
        <Item key={item.id} textValue={item.name}>
          <Avatar name={item.name} size='small' />
          <Heading>{item.name}</Heading>
          <Description>{item.description}</Description>
        </Item>
      )}
    </ListView>
  );
}
function Example() {
  const [fruits, setFruits] = useState([
    {id: 1, name: 'Apples', description: 'Sweet-tart'},
    {id: 2, name: 'Bananas', description: 'Fruity'},
    {id: 3, name: 'Grapes', description: 'Sweet-sour'},
    {id: 4, name: 'Oranges', description: 'Sweet-tart'},
  ]);

  return (
    <ListView aria-label='Fruits' items={fruits}>
      {(item) => (
        <Item key={item.id} textValue={item.name}>
          <Avatar name={item.name} size='small' />
          <Heading>{item.name}</Heading>
          <Description>{item.description}</Description>
        </Item>
      )}
    </ListView>
  );
}
function Example() {
  const [
    fruits,
    setFruits
  ] = useState([
    {
      id: 1,
      name: 'Apples',
      description:
        'Sweet-tart'
    },
    {
      id: 2,
      name: 'Bananas',
      description:
        'Fruity'
    },
    {
      id: 3,
      name: 'Grapes',
      description:
        'Sweet-sour'
    },
    {
      id: 4,
      name: 'Oranges',
      description:
        'Sweet-tart'
    }
  ]);

  return (
    <ListView
      aria-label="Fruits"
      items={fruits}
    >
      {(item) => (
        <Item
          key={item.id}
          textValue={item
            .name}
        >
          <Avatar
            name={item
              .name}
            size="small"
          />
          <Heading>
            {item.name}
          </Heading>
          <Description>
            {item
              .description}
          </Description>
        </Item>
      )}
    </ListView>
  );
}

Empty State

To show the user that the list view is empty when there is no data available you can use the renderEmptyState prop.

<ListView renderEmptyState={() => (
    <IllustratedMessage>
      <Icon name="MagnifyingGlassIcon" variant="outline" />
      <Heading>No results found</Heading>
      <Text>
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
        No results could be found. Please create a new entity or modify your
        search.
      </Text>
    </IllustratedMessage>
  )}>
  {[]}
</ListView>
<ListView
  renderEmptyState={() => (
    <IllustratedMessage>
      <Icon
        name="MagnifyingGlassIcon"
        variant="outline"
      />
      <Heading>No results found</Heading>
      <Text>
        No results could be found. Please create a new
        entity or modify your search. No results could be
        found. Please create a new entity or modify your
        search. No results could be found. Please create a
        new entity or modify your search. No results could
        be found. Please create a new entity or modify
        your search. No results could be found. Please
        create a new entity or modify your search. No
        results could be found. Please create a new entity
        or modify your search. No results could be found.
        Please create a new entity or modify your search.
        No results could be found. Please create a new
        entity or modify your search. No results could be
        found. Please create a new entity or modify your
        search. No results could be found. Please create a
        new entity or modify your search.
      </Text>
    </IllustratedMessage>
  )}
>
  {[]}
</ListView>
<ListView
  renderEmptyState={() => (
    <IllustratedMessage>
      <Icon
        name="MagnifyingGlassIcon"
        variant="outline"
      />
      <Heading>
        No results
        found
      </Heading>
      <Text>
        No results
        could be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search. No
        results could
        be found.
        Please create a
        new entity or
        modify your
        search.
      </Text>
    </IllustratedMessage>
  )}
>
  {[]}
</ListView>

Actions

The ListView supports the onAction prop which is triggered when an item from the list is clicked.

function Example() {
  const fruits = [
    {id: 1, name: 'Apples'},
    {id: 2, name: 'Bananas'},
    {id: 3, name: 'Grapes'},
    {id: 4, name: 'Oranges'}
  ];

  const handleAction = (key) => {
    alert(`Item with key ${key} was clicked`);
  };

  return (
    <ListView
      aria-label='What is your favorite fruit?'
      items={fruits}
      selectionMode='none'
      selectionStyle='highlight'
      selectedKeys={new Set(['Bananas'])}
      onAction={handleAction}
      allowReadOnlySelection
    >
      {(item) => <Item key={item.name}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const fruits = [
    {id: 1, name: 'Apples'},
    {id: 2, name: 'Bananas'},
    {id: 3, name: 'Grapes'},
    {id: 4, name: 'Oranges'}
  ];

  const handleAction = (key) => {
    alert(`Item with key ${key} was clicked`);
  };

  return (
    <ListView
      aria-label='What is your favorite fruit?'
      items={fruits}
      selectionMode='none'
      selectionStyle='highlight'
      selectedKeys={new Set(['Bananas'])}
      onAction={handleAction}
      allowReadOnlySelection
    >
      {(item) => <Item key={item.name}>{item.name}</Item>}
    </ListView>
  );
}
function Example() {
  const fruits = [
    {
      id: 1,
      name: 'Apples'
    },
    {
      id: 2,
      name: 'Bananas'
    },
    {
      id: 3,
      name: 'Grapes'
    },
    {
      id: 4,
      name: 'Oranges'
    }
  ];

  const handleAction = (
    key
  ) => {
    alert(
      `Item with key ${key} was clicked`
    );
  };

  return (
    <ListView
      aria-label="What is your favorite fruit?"
      items={fruits}
      selectionMode="none"
      selectionStyle="highlight"
      selectedKeys={new Set(
        ['Bananas']
      )}
      onAction={handleAction}
      allowReadOnlySelection
    >
      {(item) => (
        <Item
          key={item.name}
        >
          {item.name}
        </Item>
      )}
    </ListView>
  );
}

Accessibility

In order to support internationalization, provide a localized string to the aria-label prop.

API