Skip to content

Virtuoso Message List Headers and Footers

The message list component accepts Header and Footer components that can be used to display additional content at the top and bottom of the list. Additionally, StickyHeader and StickyFooter components can be used to create sticky headers and footers.

The example below features a basic list with Header and Footer specified.

import {
  VirtuosoMessageListProps,
  VirtuosoMessageList,
  useVirtuosoMethods,
  VirtuosoMessageListLicense,
  VirtuosoMessageListMethods,
} from '@virtuoso.dev/message-list'

const Header: VirtuosoMessageListProps<number, null>['Header'] = () => <div style={{ height: 30, background: 'lightblue' }}>Header</div>
const Footer: VirtuosoMessageListProps<number, null>['Footer'] = () => <div style={{ height: 30, background: 'lightblue' }}>Footer</div>

export default function App() {
  return (
    <VirtuosoMessageListLicense licenseKey="">
      <VirtuosoMessageList
        Header={Header}
        Footer={Footer}
        style={{ height: '100%' }}
        data={{ data: Array.from({ length: 100 }, (_, index) => index) }}
      />
    </VirtuosoMessageListLicense>
  )
}

Unlike the regular ones, the sticky custom components are persistently visible in the viewport, making them suitable for displaying custom UI (like pinned messages, for example). Their size is getting measured, so that the first/last messages are not obscured by them.

import {
  VirtuosoMessageListProps,
  VirtuosoMessageList,
  useVirtuosoMethods,
  VirtuosoMessageListLicense,
  VirtuosoMessageListMethods,
} from '@virtuoso.dev/message-list'

const StickyHeader: VirtuosoMessageListProps<number, null>['StickyHeader'] = () => (
  <div style={{ height: 30, background: 'lightblue' }}>Header</div>
)
const StickyFooter: VirtuosoMessageListProps<number, null>['StickyFooter'] = () => (
  <div style={{ height: 30, background: 'lightblue' }}>Footer</div>
)

export default function App() {
  return (
    <VirtuosoMessageListLicense licenseKey="">
      <VirtuosoMessageList
        StickyHeader={StickyHeader}
        StickyFooter={StickyFooter}
        style={{ height: '100%' }}
        data={{ data: Array.from({ length: 100 }, (_, index) => index) }}
      />
    </VirtuosoMessageListLicense>
  )
}

By default, the sticky header and footer will offset the list content. In some cases, we would like to avoid that - for example, the scroll to bottom button should not leave space below the messages. To achieve that, we can wrap the content with a position: absolute container.

import {
  VirtuosoMessageListProps,
  VirtuosoMessageList,
  useVirtuosoMethods,
  VirtuosoMessageListLicense,
  VirtuosoMessageListMethods,
} from '@virtuoso.dev/message-list'

const StickyHeader: VirtuosoMessageListProps<number, null>['StickyHeader'] = () => {
  return <div style={{ position: 'absolute', right: 0, top: 0, background: 'lightblue' }}>Header</div>
}

const StickyFooter: VirtuosoMessageListProps<number, null>['StickyFooter'] = () => {
  return <div style={{ position: 'absolute', right: 0, bottom: 0, background: 'lightblue' }}>Footer</div>
}

export default function App() {
  return (
    <VirtuosoMessageListLicense licenseKey="">
      <VirtuosoMessageList
        StickyHeader={StickyHeader}
        StickyFooter={StickyFooter}
        style={{ height: '100%' }}
        data={{ data: Array.from({ length: 100 }, (_, index) => index) }}
      />
    </VirtuosoMessageListLicense>
  )
}

If needed, you can combine sticky and regular components. The sticky ones will be always visible, while the regular ones will scroll with the content.

import {
  VirtuosoMessageListProps,
  VirtuosoMessageList,
  useVirtuosoMethods,
  VirtuosoMessageListLicense,
  VirtuosoMessageListMethods,
} from '@virtuoso.dev/message-list'

const StickyHeader: VirtuosoMessageListProps<number, null>['StickyHeader'] = () => (
  <div style={{ height: 30, background: 'lightblue' }}>Sticky Header</div>
)
const StickyFooter: VirtuosoMessageListProps<number, null>['StickyFooter'] = () => (
  <div style={{ height: 30, background: 'lightblue' }}>Sticky Footer</div>
)
const Header: VirtuosoMessageListProps<number, null>['Header'] = () => <div style={{ height: 30, background: 'lightgreen' }}>Header</div>
const Footer: VirtuosoMessageListProps<number, null>['Footer'] = () => <div style={{ height: 30, background: 'lightgreen' }}>Footer</div>

export default function App() {
  return (
    <VirtuosoMessageListLicense licenseKey="">
      <VirtuosoMessageList
        StickyHeader={StickyHeader}
        StickyFooter={StickyFooter}
        Header={Header}
        Footer={Footer}
        style={{ height: '100%' }}
        data={{ data: Array.from({ length: 100 }, (_, index) => index) }}
      />
    </VirtuosoMessageListLicense>
  )
}