# TableTopNotification

**Category:** Features/Display/TableTopNotification

## Design

### Description

`TableTopNotification` allows showing a message that appears between the table header and the table rows.


```tsx
import { TableTopNotification } from '@wix/patterns';
```

---

### Variations

### Base

```tsx
import { Avatar } from '@wix/design-system';
import React from 'react';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';
import { CollectionPage } from '@wix/patterns/page';
import {
  Table,
  OffsetQuery,
  TableTopNotification,
  useTableCollection,
} from '@wix/patterns';
import { useHttpClient } from '@wix/yoshi-flow-bm';

function TableNotification() {
  const httpClient = useHttpClient();

  const state = useTableCollection<Contact>({
    queryName: 'contacts-Basic',
    itemKey: (item) => item.id as string,
    itemName: (item) => item.name as string,
    fetchData: (query: OffsetQuery) => {
      const { limit, offset, search, filters } = query;
      return httpClient
        .request(
          queryContacts({
            query: { paging: { limit, offset }, filter: filters },
            search,
          }),
        )
        .then((res) => {
          const {
            data: { contacts = [], pagingMetadata },
          } = res;
          return {
            items: contacts,
            total: pagingMetadata?.total,
          };
        });
    },
    fetchErrorMessage: ({ err }) => String(err),
  });
  const collection = state.collection;
  React.useEffect(() => {
    window.setTimeout(() => {
      // some event from server that should show the notification
      collection.topNotification.text = 'Important message from server';
    }, 5000);
  }, []);

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Table
          state={state}
          columns={[
            {
              title: '',
              width: '50px',
              render: (contact) => (
                <Avatar name={contact.name} imgProps={{ src: contact.image }} />
              ),
            },
            {
              title: 'Name',
              width: '250px',
              render: (contact) => contact.name,
            },
            {
              title: 'Last Seen',
              render: (contact) => contact.lastSeen?.toLocaleString(),
            },
          ]}
          topNotification={
            <TableTopNotification
              showCloseButton
              onClose={() => {
                // console.log('onClose', collection.topNotification);
              }}
              onAfterOpen={() => {
                // console.log('onAfterOpen', collection.topNotification);
              }}
              onAfterClose={() => {
                // console.log('onAfterClose', collection.topNotification);
              }}
            />
          }
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

### Nested Table

```tsx
import { Page } from '@wix/design-system';
import React from 'react';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';
import {
  PageWrapper,
  NestedTable,
  useNestedTable,
  createNestedTableSingleEntityLevels,
  useCreateCollection,
  Filter,
  stringsArrayFilter,
  useWixPatternsContainerOverrides,
  TableTopNotification,
} from '@wix/patterns';
import { useHttpClient } from '@wix/yoshi-flow-bm';

type ContactFilters = {
  parentId: Filter<string[]>;
};

function NestedTableWithTopNotification() {
  const httpClient = useHttpClient();

  const createCollection = useCreateCollection();

  const state = useNestedTable({
    columns: [
      {
        id: 'lastSeen',
        title: 'Last Seen',
      },
    ],
    levels: createNestedTableSingleEntityLevels(5, {
      createCollection: () => {
        const collection = createCollection<Contact, ContactFilters>({
          itemName: (item) => item.info?.name?.first || '',
          queryName: 'SingleEntityNestedTable-contacts',
          filters: {
            parentId: stringsArrayFilter(),
          },
          fetchData: (query) => {
            const { limit, offset, search, filters } = query;
            return httpClient
              .request(
                queryContacts({
                  query: { paging: { limit, offset }, filter: filters },
                  search,
                }),
              )
              .then((res) => {
                const {
                  data: { contacts = [], pagingMetadata = {} },
                } = res;
                return {
                  items: contacts,
                  total: pagingMetadata.total,
                };
              });
          },
          fetchErrorMessage: ({ err }) => String(err),
        });

        return {
          collection,
          parentFilter: collection.filters.parentId,
        };
      },
      parentKey: (item) => item.parentId,
      columns: {
        lastSeen: (item) => String(item.lastSeen),
      },
      renderMainColumn: (item) => ({
        subtitle: item.level,
      }),
    }),
  });

  React.useEffect(() => {
    window.setTimeout(() => {
      // some event from server that should show the notification
      state.rootNodeCollection.collection.topNotification.text =
        'Important message from server';
    }, 0);
  }, []);

  return (
    <PageWrapper>
      <Page height="400px">
        <Page.Header title="Contacts" />

        <Page.Content>
          <NestedTable
            state={state}
            topNotification={
              <TableTopNotification
                showCloseButton
                onClose={() => {
                  // console.log('onClose', collection.topNotification);
                }}
                onAfterOpen={() => {
                  // console.log('onAfterOpen', collection.topNotification);
                }}
                onAfterClose={() => {
                  // console.log('onAfterClose', collection.topNotification);
                }}
              />
            }
          />
        </Page.Content>
      </Page>
    </PageWrapper>
  );
}
```

## API

### Extends

[SectionHelper](https://www.docs.wixdesignsystem.com/?path=/story/components-feedback--sectionhelper)

---

### Set Message

For setting a new message after an event from the server for example, use `collection.topNotification` API returned from the [useCollection](./?path=/story/common-hooks--usecollection) state object:

```ts
interface TableTopNotificationAPI {
  /**
   * The current notification message text
   * Setting it to `null` hides the notification
   */
  text: string | null | undefined;
  /**
   * Indicates whether the notificaton is shown
   */
  readonly show: boolean;
}
```


### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `onAfterClose` | `(() => unknown)` | No | - | After the notification close animation finished |
| `onAfterOpen` | `(() => unknown)` | No | - | After the notification open animation finished |
| `hideOnSearch` | `boolean` | No | `false` | hide the notification when search is applied. |
| `dataHook` | `string` | No | - | Applied as data-hook HTML attribute that can be used in the tests |
| `skin` | `"warning" \| "standard" \| "success" \| "premium" \| "danger" \| "preview" \| "experimentalDark"` | No | - | Sets the look and feel of the component |
| `appearance` | `"warning" \| "standard" \| "success" \| "premium" \| "danger" \| "preview" \| "experimentalDark"` | No | - | @deprecated use skin prop instead |
| `title` | `ReactNode` | No | - | Adds text as the title |
| `size` | `"small" \| "medium"` | No | - | Controls the component padding |
| `showCloseButton` | `boolean` | No | - | decide if to show the close button |
| `onClose` | `MouseEventHandler<HTMLElement>` | No | - | When provided, will make a close button appear and invoke it upon click |
| `onAction` | `MouseEventHandler<HTMLElement>` | No | - | When provided, will make an action button appear and invoke it upon click |
| `actionText` | `ReactNode` | No | - | Text or any child component for the action button |
| `actionDisabled` | `boolean` | No | - | Disables the action button |
| `fullWidth` | `boolean` | No | - | Set the content width to 100% |
| `layout` | `"horizontal" \| "vertical"` | No | `vertical` | Controls the component layout |
| `border` | `"standard" \| "topBottom"` | No | `standard` | Controls the component border |
| `showPrefixIcon` | `boolean` | No | - | Enables showing prefix icon |
| `prefixIcon` | `ReactNode` | No | - | Overrides default prefix icon |

## BI

### Table Top Notifications Events

 Event   |   Description   |
--------- | --------------- |
[144:136](https://bo.wix.com/data-tools/bi-catalog-app/event/144:136) | Sent when a notification is displayed, showing a message that appears between the table header and the table rows
[144:137](https://bo.wix.com/data-tools/bi-catalog-app/event/144:137) | Sent when the notification at the top of the table is dismissed, either manually or automatically



### Component load events
Event   |   Description   |
--------- | --------------- |
[144:110](https://bo.wix.com/data-tools/bi-catalog-app/event/144:110) | Sent when a Wix Patterns component starts loading
[144:111](https://bo.wix.com/data-tools/bi-catalog-app/event/144:111) | Sent when a Wix Patterns component is done loading


#### 🐪 Couldn't find what you need?
* Check our [BI Catalog](https://bo.wix.com/data-tools/bi-catalog-app?viewId=all-items-view&selectedColumns=src%2Cevid%2Cname%2Cowner%2Cproduct%2CuserType+false%2CdateUpdated%2CdateCreated+false%2CcreatedBy+false%2Cstatus&source=%5B%7B%22id%22%3A%22144%22%2C%22name%22%3A%22144+-+Cairo%22%7D%5D)
* Contact us on [#cairo-bi](https://wix.slack.com/archives/C03N53KURH9)


## Testkit

### Usage

`getTopNotification` API is exposed from the `` [testkit](./?path=/story/base-components-collections-table-table--table&tab=Testkit)


