# Internal Scroll

**Category:** Features/Display/Internal Scroll

## Design

### Internal scroll

The "internalScroll" prop enables internal scrolling within the component itself, by wrapping it inside a limited height container.

**Do:**

- Wrap the component inside a container element with a limited height. This container will provide a visual boundary for the component's content and enable scrolling within that confined space.

- Set a minimum height of at least 482px for the container. This height ensures that the component has enough space to display its content, including any placeholder states that might be utilized during loading or when there is no data to display.


**Don't:**

- Ensure that there is no scrollable parent container surrounding the table/grid component. Having a scrollable parent can lead to double scrolling behavior, which can be confusing and inconvenient for users


### Developer examples

### Full Width Section

```tsx
import { Avatar, Box, Card } from '@wix/design-system';
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import {
  OffsetQuery,
  TableGridSwitch,
  useTableGridSwitchCollection,
  useOptimisticActions,
} from '@wix/patterns';
import { contacts } from '@wix/crm';

function FullWidthInternalScroll() {

  const state = useTableGridSwitchCollection<contacts.Contact>({
    queryName: 'TableGridSwitchNarrowInternalScroll',
    paginationMode: 'offset',
    fetchData: (query: OffsetQuery) => {
      const { limit, offset, search, filters } = 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 }) => ({
        items,
        total,
      }));
    },
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchErrorMessage: () => 'Error fetching contacts',
    limit: 50,
    filters: {},
  });

  useOptimisticActions(state.collection);

  return (
    <CollectionPage height="622px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Box direction="vertical" gap="SP3">
          <Card>
            <Card.Header title="Content Above" />
            <Card.Content>
              <Box width="100%" height="130px" />
            </Card.Content>
          </Card>
          <Box
            direction="vertical"
            width="100%"
            maxHeight="482px"
            overflow="hidden"
          >
            <TableGridSwitch
              state={state}
              internalScroll
              columns={[
                {
                  id: 'avatar',
                  title: '',
                  hideable: true,
                  width: '50px',
                  render: (contact) => (
                    <Avatar
                      name={`${contact.info?.name?.first} ${contact.info?.name?.last}`}
                      imgProps={{ src: contact.info?.picture?.image }}
                    />
                  ),
                },
                {
                  title: 'Name',
                  width: '250px',
                  render: (contact) =>
                    `${contact.info?.name?.first} ${contact.info?.name?.last}`,
                },
                {
                  title: 'Last Activity',
                  render: (contact) =>
                    contact.lastActivity?.activityDate?.toLocaleString(),
                },
              ]}
            />
          </Box>
          <Card>
            <Card.Header title="Content Below" />
            <Card.Content>
              <Box width="100%" height="130px" />
            </Card.Content>
          </Card>
        </Box>
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

---

### Narrow Side Section

```tsx
import { Avatar, Box, Card } from '@wix/design-system';
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import {
  OffsetQuery,
  TableGridSwitch,
  useTableGridSwitchCollection,
  useOptimisticActions,
} from '@wix/patterns';
import { contacts } from '@wix/crm';

function NarrowInternalScroll() {

  const state = useTableGridSwitchCollection<contacts.Contact>({
    queryName: 'TableGridSwitchNarrowInternalScroll',
    paginationMode: 'offset',
    fetchData: (query: OffsetQuery) => {
      const { limit, offset, search, filters } = 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 }) => ({
        items,
        total,
      }));
    },
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchErrorMessage: () => 'Error fetching contacts',
    limit: 50,
    filters: {},
  });

  useOptimisticActions(state.collection);

  return (
    <CollectionPage height="622px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Box direction="horizontal" gap="SP3" width="100%" height="482px">
          <Box direction="vertical" width="390px" height="100%">
            <TableGridSwitch
              state={state}
              internalScroll
              columns={[
                {
                  id: 'avatar',
                  title: '',
                  hideable: true,
                  width: '50px',
                  render: (contact) => (
                    <Avatar
                      name={`${contact.info?.name?.first} ${contact.info?.name?.last}`}
                      imgProps={{ src: contact.info?.picture?.image }}
                    />
                  ),
                },
                {
                  title: 'Name',
                  width: '250px',
                  render: (contact) =>
                    `${contact.info?.name?.first} ${contact.info?.name?.last}`,
                },
              ]}
            />
          </Box>
          <Box direction="vertical" overflow="auto" flex={1} height="100%">
            <Card>
              <Card.Header title="Content" />
              <Card.Content>
                <Box width="100%" height="4000px" />
              </Card.Content>
            </Card>
          </Box>
        </Box>
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

## BI

### Custom Columns Events

 Event   |   Description   |
--------- | --------------- |
[144:112](https://bo.wix.com/data-tools/bi-catalog-app/event/144:112) | Sent when a Wix Patterns component is done loading more items (after scrolling)



### 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)


