# Grid

**Category:** Base Components/Collections/Grid/Grid

## Design

### Description

The `Grid` component displays cards in rows and columns as an alternative to tables. It is responsive, adjusting the number of cards per row based on the viewport width, and includes built-in virtualization for efficient rendering of many items without impacting performance.

#### Usage

1. Wrap your code in a `WixDesignSystemProvider` followed by a [`WixPatternsProvider`](./?path=/story/base-components-providers--wixpatternsprovider).
1. Wrap `Grid` in a [`CollectionPage`](./?path=/story/base-components-pages-collection-page--collectionpage).
1. Create a [`GridState`](./?path=/story/base-components-collections-grid-gridstate--gridstate) using [`useGridCollection()`](./?path=/story/base-components-collections-grid-usegridcollection--usegridcollection).
1. Pass the `GridState` to the `state` prop.


```tsx
import { Grid, useGridCollection } from '@wix/patterns';
```

### Demo

```tsx
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import { Grid, ToolbarTitle, useGridCollection } from '@wix/patterns';
import { Text } from '@wix/design-system';
import { Delete } from '@wix/wix-ui-icons-common';
import { contacts } from '@wix/crm';

function Demo() {

  const grid = useGridCollection<contacts.Contact>({
    queryName: 'contacts-Demo',
    paginationMode: 'offset',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query) => {
      const { limit, offset, search } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      return queryBuilder.find().then(({ items = [], totalCount: total }) => {
        return {
          items,
          total,
        };
      });
    },
    fetchErrorMessage: ({ err }) => String(err),
  });

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Grid
          title={<ToolbarTitle title="Contacts list" />}
          state={grid}
          renderItem={(item) => ({
            primaryActionProps: { label: item.info?.jobTitle },
          })}
          actionCell={(item, index, api) => {
            return {
              primaryAction: {
                text: 'Edit',
                onClick: () => {},
              },
              secondaryActions: [
                {
                  text: `Delete contact`,
                  icon: <Delete />,
                  onClick: () => {
                    api.openConfirmDeleteModal({
                      content: (
                        <Text>
                          Are you sure want to delete &nbsp;
                          <Text weight="bold">{`${item.info?.name?.first} ${item.info?.name?.last}`}</Text>{' '}
                          contact?
                        </Text>
                      ),
                      primaryButtonOnClick: () => {},
                    });
                  },
                },
              ],
            };
          }}
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

---

### Variations

### Card with a CTA that opens a modal

This example utilizes the `` `renderAddItem` prop and the `` `onClick()` prop to run a function that opens a modal.

```tsx
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import { Grid, useGridCollection } from '@wix/patterns';
import {
  AddItem,
  Box,
  CustomModalLayout,
  Input,
  Loader,
  Modal,
  TextButton,
} from '@wix/design-system';
import { contacts } from '@wix/crm';

function AddItemCardWithModal() {

  const grid = useGridCollection<contacts.Contact>({
    queryName: 'contacts-AddItemCardWithModal',
    paginationMode: 'offset',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query) => {
      const { limit, offset, search } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      return queryBuilder.find().then(({ items = [] }) => {
        const limitedItems = items.slice(0, 4);
        return {
          items: limitedItems,
          total: limitedItems.length,
        };
      });
    },
    fetchErrorMessage: ({ err }) => String(err),
  });

  const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
  const [submitted, setSubmitted] = React.useState(false);
  const [contactName, setContactName] = React.useState('');

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Grid
          state={grid}
          renderAddItem={() => (
            <AddItem
              size="medium"
              onClick={() => {
                setIsModalOpen(true);
              }}
            >
              <TextButton>New Item</TextButton>
            </AddItem>
          )}
          renderItem={(item) => ({
            primaryActionProps: { label: item.info?.jobTitle },
          })}
        />

        <Modal isOpen={isModalOpen}>
          <CustomModalLayout
            title="Create New Contact"
            primaryButtonText={submitted ? undefined : 'Save'}
            primaryButtonProps={{
              children: submitted && (
                <Box align="center" verticalAlign="middle" position="relative">
                  <Box visibility="hidden">Save</Box>
                  <Box position="absolute">
                    <Loader size="tiny" />
                  </Box>
                </Box>
              ),
            }}
            secondaryButtonText="Cancel"
            primaryButtonOnClick={() => {
              setSubmitted(true);
              window.setTimeout(() => setIsModalOpen(false), 1000);
            }}
            onCloseButtonClick={() => {
              setIsModalOpen(false);
            }}
            secondaryButtonOnClick={() => {
              setIsModalOpen(false);
            }}
            overflowY="none"
          >
            <Input
              placeholder="Contact Name"
              value={contactName}
              onChange={(e) => setContactName(e.target.value)}
            />
          </CustomModalLayout>
        </Modal>
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

### Card with a CTA that opens a popup

This example utilizes the `` `renderAddItem` prop and the `` `onClick()` prop to run a function that opens a popup.

```tsx
import React from 'react';
import { AddItem, Box, Layout, Popover, TextButton } from '@wix/design-system';
import { CollectionPage } from '@wix/patterns/page';
import {
  Grid,
  stringsArrayFilter,
  ToolbarTitle,
  useGridCollection,
} from '@wix/patterns';
import { contacts } from '@wix/crm';

function AddItemCardWithPopoverMenu() {

  const grid = useGridCollection<contacts.Contact>({
    queryName: 'contacts-AddItemCardWithPopoverMenu',
    paginationMode: 'offset',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query) => {
      const { limit, offset, search } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      return queryBuilder.find().then(({ items = [] }) => {
        const limitedItems = items.slice(0, 4);
        return {
          items: limitedItems,
          total: limitedItems.length,
        };
      });
    },
    fetchErrorMessage: ({ err }) => String(err),
    filters: {
      level: stringsArrayFilter(),
    },
  });

  const [shown, setShown] = React.useState<boolean>(false);

  const addItemChildNode = (
    <Layout cols={1} justifyItems="center">
      <Popover shown={shown} placement="bottom" appendTo="scrollParent">
        <Popover.Element>
          <TextButton
            onClick={() => {
              setShown(!shown);
            }}
          >
            New Item
          </TextButton>
        </Popover.Element>
        <Popover.Content>
          <Box padding="12px 24px" direction="vertical" maxWidth="200px">
            Can be any react node!
          </Box>
        </Popover.Content>
      </Popover>
    </Layout>
  );

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Grid
          title={<ToolbarTitle title="Contacts list" />}
          state={grid}
          preset="full"
          renderAddItem={() => (
            <AddItem
              size="medium"
              children={addItemChildNode}
              onClick={() => {
                setShown(!shown);
              }}
            />
          )}
          renderItem={(item) => ({
            key: item._id,
            primaryActionProps: { label: item.info?.jobTitle },
            title: `${item.info?.name?.first} ${item.info?.name?.last}`,
            subtitle: item.info?.jobTitle,
          })}
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

### Grid with a reduced width

This example utilizes the `` `span` prop to set the width of the Grid to 2/3 of the page.

```tsx
import React from 'react';
import { Box, Card, Cell, Layout, Page } from '@wix/design-system';
import { CollectionPage } from '@wix/patterns/page';
import { Grid, useGridCollection } from '@wix/patterns';
import { contacts } from '@wix/crm';

function TableGridSwitchTwoThirdsWithSideBar() {

  const state = useGridCollection<contacts.Contact>({
    queryName: 'contacts-GridTwoThirdsWithSideBar',
    paginationMode: 'offset',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query) => {
      const { limit, offset, search } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      return queryBuilder.find().then(({ items = [], totalCount: total }) => {
        return {
          items,
          total,
        };
      });
    },
    fetchErrorMessage: () => 'Error fetching contacts',
  });

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Layout>
          <Cell span={8}>
            <Grid
              state={state}
              actionCell={(item, index, api) => {
                return {
                  primaryAction: {
                    text: 'Edit',
                    onClick: () => {},
                  },
                };
              }}
            />
          </Cell>
          <Cell span={4}>
            <Page.Sticky>
              <Layout>
                <Cell>
                  <Card>
                    <Card.Header
                      title="Plan Info"
                      subtitle="Start by giving your plan a name and sum up what it’s about with a tagline"
                    />
                    <Card.Divider />
                    <Card.Content>
                      <Box height="300px" />
                    </Card.Content>
                  </Card>
                </Cell>
              </Layout>
            </Page.Sticky>
          </Cell>
        </Layout>
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

### Use the `preset` prop

Grids have 3 preset card types. Change them using the `preset` prop. 


        -`title`: Shows title in the card item footer.

        -`empty`: Shows a full background image.

        -`full`: Shows title and subtitle in the card item footer.

        -`footer`: Same as `full`, but also includes additional footer node.


        Default: `title`.
        

```tsx
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import { Grid, useGridCollection } from '@wix/patterns';
import { contacts } from '@wix/crm';
import { Box, Button } from '@wix/design-system';

function GridWithPreset() {
  const state = useGridCollection<contacts.Contact>({
    queryName: 'contacts-GridPreset',
    paginationMode: 'offset',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query) => {
      const { limit, offset, search } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      return queryBuilder.find().then(({ items = [], totalCount: total }) => {
        return {
          items,
          total,
        };
      });
    },
    fetchErrorMessage: () => 'Error fetching contacts',
  });

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Grid
          state={state}
          preset="full"
          renderItem={(item) => ({
            primaryActionProps: { label: item.info?.jobTitle },
            title: `${item.info?.name?.first} ${item.info?.name?.last}`,
            subtitle: item.info?.jobTitle,
            footer: (
              <Box gap="SP1" height="100%" padding="SP1" placeItems="center">
                <Button size="tiny">Edit</Button>
                <Button skin="inverted" size="tiny">
                  Preview
                </Button>
              </Box>
            ),
          })}
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

### Grid sections

This example fetches sorted collection data by `jobTitle` and then groups the grid into sections based on `jobTitle`.         For more information, see [Grid Sections](./?path=/story/features-display-grid-sections--grid-sections).

```tsx
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import { Grid, GridSections, useGridCollection } from '@wix/patterns';
import { contacts } from '@wix/crm';

function GridSectionsExample() {
  const groupBy = React.useCallback(
    (item: contacts.Contact) => item.info?.jobTitle as string,
    [],
  );

  const renderSection = React.useCallback(
    (sectionId: string) => ({
      title: sectionId,
      primaryAction: {
        id: 'show-all',
        label: 'Show All',
        onClick: () => {},
      },
    }),
    [],
  );

  const grid = useGridCollection<contacts.Contact>({
    queryName: 'GridSections',
    paginationMode: 'offset',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query) => {
      const { limit, offset, search } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      queryBuilder.ascending('info.jobTitle');

      return queryBuilder.find().then(({ items = [], totalCount: total }) => ({
        items,
        total,
      }));
    },
    fetchErrorMessage: ({ err }) => String(err),
  });

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Grid
          sections={{
            GridSections,
            groupBy,
            renderSection,
          }}
          state={grid}
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

## API

### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `search` | `boolean \| FilterElement<any> \| CollectionSearchElement` | No | `true` | Displays a search input on the right side of the table toolbar.<br> <br> Accepts a boolean or a custom React element as a parameter. When passing `false`, no search input is displayed. |
| `title` | `ToolbarTitleElement` | No | - | Displays a title at the left of a toolbar. Accepts a [ToolbarTitle](./?path=/story/features-display-toolbar--toolbartitle) component. |
| `tags` | `TagsElement<T, F>` | No | - | Enables tags feature. In this element you can pass the configuration |
| `state` | `GridState<T, F>` | Yes | - | Grid state instance created using [`useGridCollection`](./?path=/story/base-components-collections-grid-usegridcollection--usegridcollection). |
| `errorState` | `((err: unknown, params: { isOnline: boolean; retry: () => void; }) => ReactElement<any, string \| JSXElementConstructor<any>>)` | No | - | A render function to be rendered when there's an error fetching data from the server.<br> The function accepts the following parameters <br> * `err`: The error thrown by the [fetchData](./?path=/story/common-hooks--usecollection) function <br> * `isOnline`: Indicates whether internet connection is available <br> * `retry`: Retry collection fetch on failed response, similar to `collection.retryFetch` <br> Returns [`EmptyState`](https://www.docs.wixdesignsystem.com/?path=/story/components-layout--emptystate) component. |
| `views` | `CollectionViewsDropdownElement<F>` | No | - | Adds view options to the table headers. Accepts a [Views](./?path=/story/features-display-views--views) component. |
| `filters` | `CollectionToolbarFiltersElement` | No | - | Adds filters to the toolbar and/or a sliding panel. Accepts a `ToolbarFilters` component, which must have the `panelTitle` prop defined. |
| `tabs` | `TabsFilterElement<TabsFilterProps<T>>` | No | - | Displays tabs at the left of a toolbar. Accepts a [TabsFilter](./?path=/story/features-filter-components--tabsfilter) component. |
| `minCardHeight` | `MinHeight<string \| number>` | No | `300px` | Minimum height for a card's container when showing:<br> - A loader<br> - Empty state<br> - Error state <br><br> If no unit is specified, `px` is used. |
| `renderError` | `((params: { err: unknown; isOnline: boolean; retry: () => void; }) => ReactElement<any, string \| JSXElementConstructor<any>>)` | No | - | A render function to be rendered when there's an error fetching data from the server.<br> The function accepts the following parameters <br> * `err`: The error thrown by the [fetchData](./?path=/story/common-hooks--usecollection) function <br> * `isOnline`: Indicates whether internet connection is available <br> * `retry`: Retry collection fetch on failed response, similar to `collection.retryFetch` <br> Returns [`EmptyState`](https://www.docs.wixdesignsystem.com/?path=/story/components-layout--emptystate) component. @deprecated Use `errorState` instead. |
| `emptyState` | `ReactNode` | No | - | Renders when there are no items to display. Accepts a [`CollectionEmptyState`](./?path=/story/features-display-empty-states--collectionemptystate) component. |
| `noResultsState` | `ReactNode \| ((params: { hasAvailableItems: boolean; query: ComputedQuery<F>; }) => ReactNode)` | No | - | Shown when a search or filter has no results. Accepts a [`CollectionNoResultsState`](./?path=/story/features-display-empty-states--collectionnoresultsstate) component, or a function that accepts the following parameters: - `hasAvailableItems`: Indicates whether other items may be shown using other filter or search parameters. - `query`: An instance of [`ComputedQuery`](./?path=/story/common-models--computedquery) representing the query that resulted in the empty state. The function should return [`CollectionNoResultsState`](./?path=/story/features-display-empty-states--collectionnoresultsstate). |
| `topNotification` | `boolean \| TopNotificationElement \| ((params: { query: ComputedQuery<F>; }) => boolean \| TopNotificationElement \| null) \| null` | No | - | Renders a notification below the header. Accepts a [`TableTopNotification`](./?path=/story/features-display-tabletopnotification--tabletopnotification) component. |
| `summaryBar` | `ReactNode` | No | - | Display a summary bar below the toolbar. Accepts a [`SummaryBar`](./?path=/story/features-display-toolbar--summarybar) component. |
| `dragAndDropSubmit` | `DragAndDropSubmit<T, F>` | No | - | Function that submits a drop event to the server. <br> <br> The parameter is an event object containing the following details: <br> -`from: {item: T; index: number}`: The dragged item. <br> -`after: null \| [item: T; iindex: number}`: The previous dropped item. If this is the first item to be dropped, this argument is `null`. <br> -`filters`: Applied [Drag and Drop](./?path=/story/features-sort-drag-and-drop--overview) filters. @returns Promise |
| `dragAndDropBulkSubmit` | `DragAndDropBulkSubmit<T, F>` | No | - | Function that submits an array of drop events to the server. <br> <br> The parameter is an array of event objects containing the following details: <br> -`from: {item: T; index: number}`: The dragged item. <br> -`after: null \| [item: T; index: number}`: The previous dropped item. If this is the first item to be dropped, this argument is `null`. <br> -`filters`: Applied [Drag and Drop](./?path=/story/features-sort-drag-and-drop--overview) filters. <br> @returns Promise |
| `dragAndDropCancel` | `DragAndDropCancel<T, F>` | No | - | A function that cancels a drop event. <br> Supported arguments: <br> - `from: {item: T; index: number}`: The dragged item. - `after: null \| {item: T; index: number}`: The item that the dragged item was dropped after. If dropped at the head of the collection, this argument will be `null`. - `filters`: Currently applied filters. Used in cases where your server holds a unique ordering per filtering. See the `dragAndDropCategories` prop. If the move is cancelled, the function returns a toast config object with a message. Otherwise, the function will return a null value. |
| `extensionMenuItems` | `ExtensionMenuItemsType` | No | - | @deprecated It doesn't need to be passed implicitly anymore. |
| `dragAndDropReorderModeToolbar` | `ReorderModeToolbarElement \| null` | No | - | Drag and drop reorder mode toolbar. This prop accepts a `ReorderModeToolbar` component.<br> The `ReorderModeToolbar` component accepts the following props:<br> + `learnMoreUrl`: [string] A URL in the toolbar.<br> + `reorderModeTitle`: [string] A title in the toolbar. |
| `customColumns` | `CustomColumnsElement \| null` | No | - | Adds functionality to allow visitors to create choose which columns to display and in what order. Accepts a [CustomColumns](./?path=/story/features-display--customcolumns) component. |
| `multiLevelSorting` | `MultiLevelSortingElement` | No | - | Adds functionality to allow visitors to sort multiple columns simultaneously. Accepts a [MultiLevelSorting](./?path=/story/features-sort-sortable-columns-multilevelsorting--multilevelsorting) component. |
| `primaryActionButton` | `PrimaryActionButtonElement` | No | - | Adds functionality for a primary action button in the toolbar. Accepts a [PrimaryActionButton](./?path=/story/features-actions-primary-actions--primary-action-button) component. |
| `secondaryActions` | `ToolbarSecondaryActionsElement` | No | - | Secondary buttons w/o PopoverMenu component to be rendered on the toolbar. |
| `moreActions` | `MoreActionsElement` | No | - | A [`MoreActions`](./?path=/story/features-actions-more-actions--more-actions) component to be rendered on the header. |
| `AddApplyFiltersButton` | `AddApplyFiltersButtonType` | No | - | Apply filter button implementation: `import { AddApplyFiltersButton } from '@wix/patterns';` <br> Add `Apply` button to the filters panel footer. Panel filters will be applied only after the button is clicked. |
| `internalScroll` | `boolean` | No | - | Indicates whether the table should have an [internal scroll](./?path=/story/features-display-internal-scroll--internal-scroll) instead of the default page scroll. |
| `showFieldTypeIcons` | `boolean` | No | `false` | When true, renders prefix icons for field types in column headers, filters, and the customize-columns panel. Each column and filter should have a `fieldType` property set so Cairo can render the matching icon. |
| `showTitleBar` | `boolean` | No | `true` | Indicates whether to show Table Title Bar or not. Note: if you pass `showTitleBar = false` title bar is not removed from the DOM. For better accessibility column titles should be defined as well. |
| `exportButton` | `ReactElement<any, string \| JSXElementConstructor<any>>` | No | - | A [`<ExportButton />`](./?path=/story/features-export--exportto) react element to be added to the toolbar |
| `importButton` | `ReactElement<any, string \| JSXElementConstructor<any>>` | No | - | A [`<ImportButton />`] react element to be added to the toolbar. |
| `exportModal` | `ReactElement<any, string \| JSXElementConstructor<any>>` | No | - | A [`<ExportModal />`](./?path=/story/features-export--exportto#CTA_is_out_of_the_table) react element to be rendered in table's context. |
| `importModal` | `ReactElement<any, string \| JSXElementConstructor<any>>` | No | - | A [`<ImportModal />`] react element to be rendered in table's context. |
| `dragAndDropCategories` | `(keyof F)[][] \| null` | No | - | By default, drag and drop works only without filters. To enable drag and drop with filters, pass an array of filters to this prop. The functionality will then work only for the specified filters, and to enable without filters, you must pass an empty array. For more information, see the [Drag and Drop Overview](//?path=/story/features-sort-drag-and-drop--overview). |
| `dragAndDrop` | `{ SortableContext: (<T, F extends FiltersMap>(props: GridSortableContextProps<T, F>) => Element) & { displayName: string; }; DraggableCard: (<T, F extends FiltersMap>(props: DraggableCardProps<...>) => Element) & { ...; }; DraggableCardOverlay: (<T, F extends FiltersMap>(props: DraggableCardOverlayProps<...>) => Rea...` | No | - | Adds functionality to allow visitors to reorder items manually. For more information, see the [Drag and Drop Overview](./?path=/story/features-sort-drag-and-drop--overview). |
| `bulkActionToolbar` | `BulkActionToolbarRenderProp<T, F>` | No | - | A toolbar for performing bulk actions on multiple items.<br> <br> Supported parameters: <br> -`selectedValues`: [array] Items that are checked in the selection column. <br> -`uncheckedValues`: [array] Items that are unchecked in the selection column. <br> -`isSelectAll`: [bool] Whether **Select All** is checked. <br> -`openModal`: [func] Opens a modal that contains the component from `bulkActionModal` render prop. <br> -`clearSelection`: [func] Clears all selections. Call this after the action on the selected items finishes. <br> -`total`: [number] Total number of items in the server. <br> -`openConfirmModal`: [func] Opens a `<MessageModalLayout>` to confirm an action is about to be applied to the selected items. <br> -`query`: [object] Current paging, sorting, and filtering. Often used together with bulk actions, such as `updateAll`. <br> |
| `sections` | `{ GridSections: (<T, F extends FiltersMap>(props: GridSectionsContentProps<T, F>) => Element) & { displayName: string; }; groupBy: GroupBy<T>; renderSection?: RenderSection<...>; }` | No | - | Creates [grid sections](./?path=/story/features-display-grid-sections--grid-sections) that group data based on the values of a specific field. |
| `actionCell` | `ActionCell<T, F>` | No | - | Adds an action on the grid item. For example, a delete button to delete an item. Accepts an [`ActionCellProps`](https://www.docs.wixdesignsystem.com/?path=/story/components-lists-table--tableactioncell) object, or a function that returns an `ActionCellProps` object. |
| `renderAddItem` | `(() => ReactElement<AddItemProps, string \| JSXElementConstructor<any>>)` | No | - | A function that renders [`<AddItem>`](https://www.docs.wixdesignsystem.com/?path=/story/components-actions--additem&activeTab=Description&globals=backgrounds.value:!hex(F8F8F8);backgrounds.grid:false) after all cards in a gallery. <br><br> The `<AddItem>` card will not show when filters are applied unless the filter is defined with the persistent option. |
| `imagePlacement` | `"top" \| "side"` | No | - | Sets placement of a background image. |

## Accessibility

### Description

## What we did
In this component we added a Live Region which announces the results which are rendered on the screen visually.

## Why is it important
Screen reader users, which have a severe visual impairment need to be notified when there is a change in the page layout or there is some error or status messages that appear. In some cases, in order not to interfere with the users current position on the page, the focus should be kept in place and the status should be announced (in case of search, tabs or adding an item from the collection header). In other cases, specifically if the button on which the user clicked disappears or becomes disabled, both techniques of focus management and live region should be used in parallel (in case of filter, or adding/removing an item from the collection).

Due to the fact that this all happens behind the scenes you can experience it only with a screen reader on in this video:


## What is included in the component?
Announcements of the total number of results which were found after performing a search, after applying a filter, when navigating between tabs and when changing the view in the dropdown.


