Skip to main content

List Invites Block

ListInvites is an invite management table with pagination, row actions, and block composition.

Installation

npm install @nodeblocks/frontend-list-invites-block

What You Need

ItemWhy it matters
labelsCopy for headers, statuses, empty state, and actions
dataRows (id, name, email, status)
listInvitesTitlePage title in the header
onClickActionHandler for the invite-user button
isLoading (optional)Show the loading state
pagination (optional)Client-side or server-driven page changes
rowHref + onNavigate (optional)Make rows clickable with app routing
statusMatch (optional)Map raw row.status values to status labels
shouldShowDropdownMenu (optional)Hide row action menus for matching rows
resolveRowAction + handlers (optional)Per-row activate/deactivate menu actions
Controlled component

ListInvites does not own table or pagination state. Keep data, pagination.currentPage, and pagination.onPageChange in your app (slice rows per page on the client, or fetch a page from your API). Pass rowHref and onNavigate together to make rows clickable.

Row shape and status labels

Each row is a ListInvitesRowData object: id, name, email, and status. The generated status column compares row.status with statusMatch (default active / inactive / pending) to choose the displayed status label. Row actions require labels.rowActions, resolveRowAction, and the matching handler (onItemActivate / onItemDeactivate); shouldShowDropdownMenu can hide them per row. statusMatch does not choose row actions.

Code Examples

Live Editor
function Example() {
  const allInviteData = [
    {id: '0', name: 'User 0', email: 'user0@example.com', status: 'pending'},
    {id: '1', name: 'User 1', email: 'user1@example.com', status: 'active'},
    {id: '2', name: 'User 2', email: 'user2@example.com', status: 'inactive'},
    {id: '3', name: 'User 3', email: 'user3@example.com', status: 'pending'},
    {id: '4', name: 'User 4', email: 'user4@example.com', status: 'active'},
    {id: '5', name: 'User 5', email: 'user5@example.com', status: 'inactive'},
  ];

  const labels = {
    emptyStateMessage: 'No invites found',
    actions: {inviteUser: 'Invite User'},
    headerRow: {name: 'Name', email: 'Email', status: 'Status'},
    cellData: {statusActive: 'Active', statusInactive: 'Inactive', statusPending: 'Pending'},
    rowActions: {activate: 'Activate Invite', deactivate: 'Deactivate Invite'},
  };

  const [currentPage, setCurrentPage] = React.useState(1);
  const [lastAction, setLastAction] = React.useState('Select an invite action to see feedback here.');
  const itemsPerPage = 5;
  const totalPages = Math.ceil(allInviteData.length / itemsPerPage);
  const startIndex = (currentPage - 1) * itemsPerPage;
  const paginatedData = allInviteData.slice(startIndex, startIndex + itemsPerPage);

  return (
    <>
      <ListInvites
        listInvitesTitle="Manage Invites"
        labels={labels}
        data={paginatedData}
        rowHref={row => `/invites/${row.id}`}
        onNavigate={path => setLastAction(`Navigate: ${path}`)}
        onClickAction={() => setLastAction('Invite user clicked')}
        onItemActivate={id => setLastAction(`Activate: ${id}`)}
        onItemDeactivate={id => setLastAction(`Deactivate: ${id}`)}
        resolveRowAction={row => {
          if (row.id === '0') return undefined;
          return row.status === 'inactive' ? ['activate'] : ['deactivate'];
        }}
        pagination={{
          currentPage,
          totalPages,
          onPageChange: setCurrentPage,
        }}
      />
      <div style={{marginTop: 12, color: '#475569', fontSize: 13}}>{lastAction}</div>
    </>
  );
}
Result
Loading...

Important Props

Core Props

PropTypeRequiredDefaultDescription
labels{ emptyStateMessage: string; actions: { inviteUser: string }; headerRow: { name: string; email: string; status: string }; cellData: { statusActive: string; statusInactive: string; statusPending: string }; rowActions?: { activate: string; deactivate: string } }Yes-UI copy for headers, statuses, empty state, and actions
dataListInvitesRowData[]Yes-Table rows (id, name, email, status)
listInvitesTitleReactNodeYes-Header title
onClickAction() => voidYes-Invite-user button handler
isLoadingbooleanNoundefinedShows the loading state when true
pagination{ currentPage: number; totalPages: number; onPageChange: (page: number) => void; className?: string }NoundefinedPage controls; pages are counted from 1
rowHref(row: ListInvitesRowData) => stringNoundefinedBuild a row link target; pair with onNavigate to make rows clickable
onNavigate(to: string) => voidNoundefinedCalled when a clickable row is activated
shouldShowDropdownMenu(row: ListInvitesRowData) => booleanNoundefinedReturn false to hide row action menu items for a row
resolveRowAction(row: ListInvitesRowData) => ('activate' | 'deactivate')[] | undefinedNoundefinedSelects which row actions to show
statusMatch{ active: string; inactive: string; pending: string }No{ active: 'active', inactive: 'inactive', pending: 'pending' }Maps raw row.status values to the generated status labels
onItemActivate(id: string) => voidNoundefinedHandles activate row actions
onItemDeactivate(id: string) => voidNoundefinedHandles deactivate row actions

Row actions require labels.rowActions and resolveRowAction. If a handler is missing, that action is omitted from the menu.

Content Props

labels keys (all required on the root labels object except rowActions):

PropTypeRequiredDefaultDescription
labels.emptyStateMessagestringYes-Empty table message
labels.actions.inviteUserstringYes-Header button label
labels.headerRow.namestringYes-Name column header
labels.headerRow.emailstringYes-Email column header
labels.headerRow.statusstringYes-Status column header
labels.cellData.statusActivestringYes-Label for active status
labels.cellData.statusInactivestringYes-Label for inactive status
labels.cellData.statusPendingstringYes-Label for pending status
labels.rowActions.activatestringNoundefinedRow menu label for activate action
labels.rowActions.deactivatestringNoundefinedRow menu label for deactivate action

Subcomponents (compound layout):

ComponentPropTypeRequiredDefaultDescription
TitlechildrenReactNodeNoRoot listInvitesTitleCustom title markup
TitlelistInvitesTitleReactNodeNoRoot listInvitesTitleTitle text when children is not provided
ActionchildrenReactNodeNoInvite button from root labels.actions.inviteUser and onClickActionCustom action markup
Actionlabels{ actions: { inviteUser: string } }NoRoot labelsButton label source
ActiononClickAction() => voidNoRoot handlerInvite button click handler
HeaderchildrenReactNodeNoundefinedHeader wrapper content
LoaderchildrenReactNodeNoCircularProgressLoading indicator
ContentchildrenReactNodeNoundefinedWraps the loader and/or table
ContentisLoadingbooleanNoundefinedForwards loading state to the content wrapper
Tablelabels{ emptyStateMessage: string; actions: { inviteUser: string }; headerRow: { name: string; email: string; status: string }; cellData: { statusActive: string; statusInactive: string; statusPending: string }; rowActions?: { activate: string; deactivate: string } }NoRoot labelsGenerates default columns and row actions
TabledataListInvitesRowData[]NoRoot dataRows to render
TablerowHref(row: ListInvitesRowData) => stringNoRoot rowHrefRow link target
TableonNavigate(to: string) => voidNoRoot onNavigateRow navigation handler
TableonItemActivate(id: string) => voidNoRoot onItemActivateHandles activate row actions
TableonItemDeactivate(id: string) => voidNoRoot onItemDeactivateHandles deactivate row actions
TableshouldShowDropdownMenu(row: ListInvitesRowData) => booleanNoRoot shouldShowDropdownMenuHides row menus for matching rows
TableresolveRowAction(row: ListInvitesRowData) => ('activate' | 'deactivate')[] | undefinedNoRoot resolveRowActionChooses row menu actions
TablestatusMatch{ active: string; inactive: string; pending: string }NoRoot statusMatchCustom status mapping
Paginationpagination{ currentPage: number; totalPages: number; onPageChange: (page: number) => void; className?: string }NoRoot paginationPage controls
PaginationdataListInvitesRowData[]NoRoot dataRow count for pagination
PaginationisLoadingbooleanNoRoot isLoadingHides pagination while loading

Title, Action, Header, Loader, Content, Table, and Pagination are ListInvites.Title, etc. ListInvites.Table also accepts custom columns, rowActions, rowMenu, actionColumn, and onRowClick when you need fully custom grid behavior.

Layout and Composition Props

PropTypeRequiredDefaultDescription
childrenBlocksOverride | ReactNodeNoundefinedCompound JSX children or function override returning blocks and blockOrder
classNamestringNoundefinedClass on the root container (nbb-list-invites-container)
sxSxPropsNoundefinedMUI system styles for the root

ListInvites inherits StackProps passthrough except children. Render order without overrides is header, content, pagination; defaultBlockOrder is header, content, pagination (defaultBlocks keys: title, action, header, loader, content, table, pagination).

Default UI Blocks

BlockBuilt onNotes
ListInvites (root)StackTable shell; renders header/content/pagination; empty state uses PersonOutlined
ListInvites.TitleTypographyTitle text from listInvitesTitle
ListInvites.ActionButtonInvite-user action with PeopleOutlineOutlined icon
ListInvites.HeaderStackHeader wrapper for title and actions
ListInvites.LoaderCircularProgressLoading state
ListInvites.ContentBoxContent wrapper for loader, empty state, or grid
ListInvites.TableStack + TableContainer + TableData grid; supports custom columns, row actions, row menu, and row click behavior
ListInvites.PaginationStack + PaginationPage controls

TypeScript

import { ListInvites, type ListInvitesRowData } from '@nodeblocks/frontend-list-invites-block';

const labels = {
emptyStateMessage: 'No invites found',
actions: {inviteUser: 'Invite User'},
headerRow: {name: 'Name', email: 'Email', status: 'Status'},
cellData: {statusActive: 'Active', statusInactive: 'Inactive', statusPending: 'Pending'},
rowActions: {activate: 'Activate Invite', deactivate: 'Deactivate Invite'},
};

const rows: ListInvitesRowData[] = [{id: '1', name: 'Alex', email: 'alex@example.com', status: 'pending'}];

<ListInvites
listInvitesTitle="Manage Invites"
labels={labels}
data={rows}
onClickAction={() => {}}
rowHref={row => `/invites/${row.id}`}
onNavigate={(path) => window.location.assign(path)}
/>;