Collection hooks package
Use the Cloudscape collection hooks package to handle data operations in collection components.
On this page
Did this page help you?
Tell us more - optional
Overview
Cloudscape provides table and cards components to display collections of resources. These components display static datasets. Operations on these datasets (such as filtering, sorting, and pagination) should happen outside of these components.
Client-side collections
The @cloudscape-design/collection-hooks
package provides utilities to handle filtering, sorting, or pagination operations when the full dataset describing the collection can be fetched on the client side, without requiring further asynchronous calls. This use case is called client-side collection.
Server-side collections
If your dataset has to be fetched asynchronously upon filtering, sorting, and pagination operations, don’t use the @cloudscape-design/collection-hooks
package. Instead, implement the fetching, filtering, selection, pagination, and sorting yourself. This use case is called server-side collection.
Install the package
This package is published to NPM as @cloudscape-design/collection-hooks .
For more information, see the package installation guide.
Using with React
This package exports the useCollection
React hook . It takes the original collection items and a configuration, and returns filtered, sorted, and paginated content, according to your configuration.
Code example
Example below uses text filtering. Check out the official demo that uses property filtering feature of the collection hooks.
Preview
Instances (25)
ID | Availability zone | State | |
---|---|---|---|
us-east-1c | Healthy | ||
us-east-1a | Healthy | ||
us-east-1d | Healthy | ||
us-east-1b | Unhealthy | ||
us-east-1a | Healthy | ||
us-east-1c | Healthy | ||
us-east-1e | Healthy | ||
us-east-1b | Healthy | ||
us-east-1c | Healthy | ||
us-east-1d | Healthy |
Code
The following code uses React and JSX syntax.
'use client';
import React, { useState } from 'react';
import { useCollection } from '@cloudscape-design/collection-hooks';
import {
Box,
Button,
CollectionPreferences,
Header,
Pagination,
Table,
TextFilter,
} from '@cloudscape-design/components';
import allItems from './data';
import { columnDefinitions, getMatchesCountText, paginationLabels, collectionPreferencesProps } from './table-config';
function EmptyState({ title, subtitle, action }) {
return (
<Box textAlign="center" color="inherit">
<Box variant="strong" textAlign="center" color="inherit">
{title}
</Box>
<Box variant="p" padding={{ bottom: 's' }} color="inherit">
{subtitle}
</Box>
{action}
</Box>
);
}
export default function CollectionHooksTable() {
const [preferences, setPreferences] = useState({
pageSize: 10,
contentDisplay: [
{ id: 'id', visible: true },
{ id: 'availabilityZone', visible: true },
{ id: 'state', visible: true },
],
});
const { items, actions, filteredItemsCount, collectionProps, filterProps, paginationProps } = useCollection(
allItems,
{
filtering: {
empty: <EmptyState title="No instances" action={<Button>Create instance</Button>} />,
noMatch: (
<EmptyState
title="No matches"
action={<Button onClick={() => actions.setFiltering('')}>Clear filter</Button>}
/>
),
},
pagination: { pageSize: preferences.pageSize },
sorting: {},
selection: {},
}
);
const { selectedItems } = collectionProps;
return (
<Table
{...collectionProps}
selectionType="multi"
header={
<Header
counter={selectedItems.length ? `(${selectedItems.length}/${allItems.length})` : `(${allItems.length})`}
>
Instances
</Header>
}
columnDefinitions={columnDefinitions}
columnDisplay={preferences.contentDisplay}
items={items}
pagination={<Pagination {...paginationProps} ariaLabels={paginationLabels} />}
filter={
<TextFilter
{...filterProps}
countText={getMatchesCountText(filteredItemsCount)}
filteringAriaLabel="Filter instances"
/>
}
preferences={
<CollectionPreferences
{...collectionPreferencesProps}
preferences={preferences}
onConfirm={({ detail }) => setPreferences(detail)}
/>
}
/>
);
}
Using expandable rows
If you want a table to use hierarchical data presentation with expandable rows, define nested items structure with expandable rows configuration of the useCollection
hook:
const allItems = [
{ id: '1', type: 'group', name: 'Devices', parentId: null },
{ id: '1.1', type: 'device', name: 'Smartphone', parentId: '1' },
{ id: '1.2', type: 'device', name: 'Laptop', parentId: '1' },
{ id: '2', type: 'group', name: 'Auxillary', parentId: null }
];
const { items: rootItems, collectionProps } = useCollection(allItems, {
expandableRows: {
getId: (item) => item.id,
getParentId: (item) => item.parentId,
}
});
return (<Table items={rootItems} columnDefinitions={columnDefinitions} {...collectionProps} />);
Note that it is important to define expandable rows via collection hooks so that filtering, sorting, and pagination work correctly.
Using multi-select tokens
To use multi-select tokens, pass tokenType="enum"
to the desired properties and operators. For example:
const { items, propertyFilterProps, ... } = useCollection({
propertyFiltering: {
filteringProperties: [
{
key: 'state',
operators: [
// Set token type for equals and not equals operators as enum so that
// the default many-to-one matching logic is used.
// In the property filter, the corresponding multi-choice form and formatter will be used.
{ operator: '=', tokenType: "enum" },
{ operator: '!=', tokenType: "enum" },
// Keep token type for contains and not contains operators as is.
':',
'!:',
],
// ...
}
]
}
});
Using custom operator matchers
If you want to override the default filtering logic, use a match function on the extended operator notation:
const { items, propertyFilterProps, ... } = useCollection({
propertyFiltering: {
filteringProperties: [
// Using custom matcher to support searching with a comma-separated list
{
key: 'status',
operators: [
{ operator: '=', match: (itemValue, tokenValue) => tokenValue.split(',').includes(itemValue) },
{ operator: '!=', match: (itemValue, tokenValue) => !tokenValue.split(',').includes(itemValue) },
],
...
},
// Using predefined date matcher
{
key: 'launchDate',
operators: [
{ operator: '=', match: 'date' },
{ operator: '!=', match: 'date' },
{ operator: '<', match: 'date' },
{ operator: '<=', match: 'date' },
{ operator: '>', match: 'date' },
{ operator: '>=', match: 'date' },
],
...
},
// Using predefined datetime matcher
{
key: 'lastEventAt',
operators: [
{ operator: '=', match: 'datetime' },
{ operator: '!=', match: 'datetime' },
{ operator: '<', match: 'datetime' },
{ operator: '<=', match: 'datetime' },
],
...
},
]
}
});
Note that overrides are done per operator.
Intercepting event listeners
If you want to define a custom behavior upon user actions, ensure you always call the method created by the collection hook:
const { ..., paginationProps } = useCollection(...);
return (
<Table
...
pagination={
<Pagination
{...paginationProps}
onChange={event => {
myCustomFunction(event);
paginationProps.onChange(event);
}}
/>
}
/>
);
API
useCollection(allItems: Array, configuration: Configuration): Result
Configuration
Name | Type | Description |
---|---|---|
filtering | Object | Filtering configuration. If you want to activate filtering with default settings, provide an empty object. |
filteringFunction | (item: T, text: string, fields?: string[]) => boolean | Custom function to filter items. The default value is a function that loops through all items keys (unless |
fields | string[] | Array of keys within the item object whose values are taken into account by the default filteringFunction. |
defaultFilteringText | string | Initial filtering value on the first render. |
empty | React.ReactNode | Content to display in the table/cards empty slot when there are no items initially provided. |
noMatch | React.ReactNode | Content to display in the table/cards empty slot when filtering returns no matched items. |
propertyFiltering | Object | Configuration for property filtering. |
filteringProperties | readonly PropertyFilterProperty[] | Array of properties by which the data set is going to be filtered. Individual items have following properties:
|
filteringFunction | (item: T, query: PropertyFilterQuery) => boolean; | Custom function to filter items. The default value is a function that takes values under the |
defaultQuery | PropertyFilterQuery | Initial query on the first render. |
empty | React.ReactNode | Content to display in the table/cards empty slot when there are no items initially provided. |
noMatch | React.ReactNode | Content to display in the table/cards empty slot when filtering returns no matched items. |
sorting | Object | Sorting configuration. If you want to use sorting with default settings, provide an empty object. This feature is only applicable for the table component. |
defaultState | Object | Initial sorting state on the first render. This is an object with two properties:
|
pagination | Object | Pagination configuration. If you want to paginate items using default settings, provide an empty object. |
pageSize | number | Value of the desired page size. |
defaultPage | number | Page number for the initial render. |
selection | Object | Selection configuration. If you want to use the selection feature with default settings, provide an empty object. |
defaultSelectedItems | ReadonlyArray<T> | Items selected on the initial render. The items are matched by |
keepSelection | boolean | If set to |
trackBy | string | ((item: T) => string) | Property of an item that uniquely identifies it. It is used for matching the objects in |
expandableRows | Object | Expandable rows configuration. |
getId | (item: T) => string | Property of an item that uniquely identifies it. It is used to make a nested items structure from of a plain list of items, and to match objects |
getParentId | (item: T) => null | string | Property of an item that identifies its parent by ID. For root items the function must return |
defaultExpandedItems | ReadonlyArray<T> | Items expanded on the initial render. The items are matched by |
Result
Name | Type | Description |
---|---|---|
items | ReadOnlyArray<T> | Table items on the current page with filtering, sorting, and pagination applied. In tables with expandable rows, only root items are returned. |
allPageItems | ReadOnlyArray<T> | Table items across all pages with filtering and sorting applied. In tables with expandable rows, only root items are returned. |
filteredItemsCount | number | Total numbers of items matching the current filter, ignoring the pagination. Use this value for creating the localized matches count text for the TextFilter component. |
firstIndex | number | The 1-based index of the first item returned in the |
totalItemsCount | number | The total count of all items in a table. For tables with expandable rows it only includes the top-level items. |
actions | Object | An object with functions to perform different actions. |
setFiltering | (filteringText: string): void | Sets new filtering text. |
setPropertyFiltering | (query: Query): void | Sets new filtering query. |
setSorting | (state: SortingState): void | Sets new sorting state. |
setCurrentPage | (currentPageIndex: number): void | Sets current page in pagination. |
setSelectedItems | (selectedItems: ReadonlyArray): void | Sets the list of currently selected items. |
setExpandedItems | (expandedItems: ReadonlyArray): void | Sets the list of currently expanded items. |
collectionProps | Object | Props object to spread on the table/cards component. For more details see the table component API documentation. |
empty | React.ReactNode | |
sortingColumn | SortingColumn<T> | |
sortingDescending | boolean | |
onSortingChange | (event: CustomEvent<SortingState>) => void | |
selectedItems | ReadonlyArray<T> | |
onSelectionChange | (event: CustomEvent<SelectionChangeDetail<T>>) => void | |
expandableRows | Object | Expandable rows configuration of the Table component (matches TableProps.ExpandableRows<T>). |
trackBy | string | ((item: T) => string) | |
ref | React.RefObject<CollectionRef> | |
filterProps | Object | Props object to spread on the TextFilter component. |
disabled | boolean | |
filteringText | string | |
onChange | (event: CustomEvent<ChangeDetail>) => void | |
propertyFilterProps | Object | Props object to spread on the PropertyFilter component. |
query | PropertyFilterQuery | |
onChange | (event: CustomEvent<Query>) => void | |
filteringProperties | readonly PropertyFilterProperty[] | |
filteringOptions | readonly PropertyFilterOption[] | |
paginationProps | Object | Props object to spread on the Pagination component. |
disabled | boolean | |
currentPageIndex | number | |
pagesCount | number | |
onChange | (event: CustomEvent<ChangeDetail>) => void |