List Invites Block
The ListInvites Component is a fully customizable and accessible invite management interface built with React and TypeScript. It provides a complete tabular invite listing experience with modern design patterns, action dropdowns, pagination support, loading states, and flexible customization options for advanced invite management applications.
🚀 Installation
npm install @nodeblocks/frontend-list-invites-block@0.1.1
📖 Usage
import {ListInvites} from '@nodeblocks/frontend-list-invites-block';
- Basic Usage
- Advanced Usage
function BasicListInvites() {
const [isLoading, setIsLoading] = useState(false);
const inviteData = [
{
id: '1',
name: 'John Doe',
email: 'john.doe@example.com',
status: 'pending'
},
{
id: '2',
name: 'Jane Smith',
email: 'jane.smith@example.com',
status: 'accepted'
},
{
id: '3',
name: 'Bob Johnson',
email: 'bob.johnson@example.com',
status: 'expired'
}
];
const labels = {
emptyStateMessage: 'No invites found',
actions: {
inviteUser: 'Invite User'
},
headerRow: {
name: 'Name',
email: 'Email',
status: 'Status'
},
rowActions: {
reject: 'Reject Invite'
},
unsetDateMessage: 'No date set'
};
const handleItemReject = (inviteId) => {
console.log('Reject invite:', inviteId);
};
const handleClickAction = () => {
console.log('Invite user clicked');
};
const handleNavigate = (path) => {
console.log('Navigate to:', path);
};
const getRowHref = (row) => `/invites/${row.id}`;
return (
<ListInvites
listInvitesTitle="Manage Invites"
labels={labels}
isLoading={isLoading}
onNavigate={handleNavigate}
onClickAction={handleClickAction}
onItemReject={handleItemReject}
data={inviteData}
rowHref={getRowHref}>
<ListInvites.Header style={{display: 'flex', justifyContent: 'space-between', padding: '16px'}}>
<ListInvites.Title />
<ListInvites.Action />
</ListInvites.Header>
<ListInvites.Content>
{isLoading ? (
<ListInvites.Loader />
) : (
<ListInvites.Table />
)}
</ListInvites.Content>
</ListInvites>
);
}
function AdvancedListInvites() {
const [isLoading, setIsLoading] = useState(false);
const inviteData = [
{
id: '1',
name: '田中太郎',
email: 'tanaka.taro@company.jp',
status: '承認待ち'
},
{
id: '2',
name: '佐藤花子',
email: 'sato.hanako@company.jp',
status: '承認済み'
},
{
id: '3',
name: '鈴木次郎',
email: 'suzuki.jiro@company.jp',
status: '期限切れ'
},
{
id: '4',
name: 'ロバート・ジョンソン',
email: 'robert.johnson@global.com',
status: '拒否済み'
}
];
const labels = {
emptyStateMessage: '招待状が見つかりません',
actions: {
inviteUser: '新しいメンバーを招待'
},
headerRow: {
name: '氏名',
email: 'メールアドレス',
status: 'ステータス'
},
rowActions: {
reject: '招待を取り消し'
},
unsetDateMessage: '日付未設定'
};
const handleItemReject = (inviteId) => {
console.log('招待を拒否:', inviteId);
};
const handleClickAction = () => {
console.log('新しいメンバーを招待');
};
const handleNavigate = (path) => {
console.log('ナビゲート:', path);
};
const getRowHref = (row) => `/invites/${row.id}`;
return (
<ListInvites
listInvitesTitle="👥 チーム招待管理"
labels={labels}
isLoading={isLoading}
onNavigate={handleNavigate}
onClickAction={handleClickAction}
onItemReject={handleItemReject}
data={inviteData}
rowHref={getRowHref}
style={{
background: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)',
borderRadius: '24px',
padding: '24px',
margin: '20px',
boxShadow: '0 20px 60px rgba(0,0,0,0.12)',
border: '1px solid rgba(255,255,255,0.3)'
}}>
{({ defaultBlocks, defaultBlockOrder }) => ({
blocks: {
// Enhanced header with modern styling
header: {
...defaultBlocks.header,
props: {
...defaultBlocks.header.props,
style: {
background: 'rgba(255, 255, 255, 0.8)',
borderRadius: '16px',
padding: '24px',
marginBottom: '24px',
backdropFilter: 'blur(10px)',
border: '1px solid rgba(255,255,255,0.4)',
boxShadow: '0 8px 32px rgba(0,0,0,0.08)',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}
}
},
// Enhanced title with gradient styling
title: {
...defaultBlocks.title,
props: {
...defaultBlocks.title.props,
style: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
fontSize: window.innerWidth <= 800 ? '24px' : '32px',
fontWeight: 'bold',
margin: '0'
}
}
},
// Enhanced action button
action: {
...defaultBlocks.action,
props: {
...defaultBlocks.action.props,
style: {
display: 'flex',
alignItems: 'center',
gap: '12px'
},
children: (
<button
onClick={handleClickAction}
style={{
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
border: 'none',
borderRadius: '12px',
padding: '12px 24px',
color: 'white',
fontSize: '14px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'all 0.3s ease',
boxShadow: '0 4px 16px rgba(102, 126, 234, 0.3)',
display: 'flex',
alignItems: 'center',
gap: '8px'
}}
onMouseOver={(e) => {
e.target.style.transform = 'translateY(-2px)';
e.target.style.boxShadow = '0 8px 24px rgba(102, 126, 234, 0.4)';
}}
onMouseOut={(e) => {
e.target.style.transform = 'translateY(0)';
e.target.style.boxShadow = '0 4px 16px rgba(102, 126, 234, 0.3)';
}}>
<span style={{ fontSize: '16px' }}>➕</span>
{labels.actions.inviteUser}
</button>
)
}
},
// Enhanced content container
content: {
...defaultBlocks.content,
props: {
...defaultBlocks.content.props,
style: {
background: 'rgba(255, 255, 255, 0.9)',
borderRadius: '20px',
padding: '0',
backdropFilter: 'blur(10px)',
border: '1px solid rgba(255,255,255,0.4)',
boxShadow: '0 8px 32px rgba(0,0,0,0.08)',
overflow: 'hidden'
}
}
},
// Enhanced table with professional styling
table: {
...defaultBlocks.table,
props: {
...defaultBlocks.table.props,
style: {
borderRadius: '20px',
overflow: 'hidden',
boxShadow: '0 4px 20px rgba(0,0,0,0.08)'
}
}
}
},
blockOrder: defaultBlockOrder
})}
</ListInvites>
);
}
🔧 Props Reference
Main Component Props
| Prop | Type | Default | Description |
|---|---|---|---|
listInvitesTitle | ReactNode | Required | Title for the invites section |
labels | TableLabels | Required | Labels object for table headers, actions, and messages |
isLoading | boolean | undefined | Whether the table is currently loading |
onNavigate | (to: string) => void | Required | Callback function for navigation |
onClickAction | () => void | Required | Callback function for the main action button |
onItemReject | (inviteId: string) => void | Required | Callback function when invite is rejected |
data | ListInvitesRowData[] | Required | Array of invite data objects |
rowHref | (row: ListInvitesRowData) => string | Required | Function to generate row link URLs |
pagination | {currentPage: number; onPageChange: (page: number) => void; totalPages: number} | From context | Pagination configuration |
className | string | undefined | Additional CSS class name for styling the container |
children | BlocksOverride | undefined | Custom block components to override default rendering |
Note: This component inherits all HTML div element props.
Sub-Components
The ListInvites component provides several sub-components. All sub-components receive their default values from the main component's context and can override these values through props.
ListInvites.Header
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default header rendering |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML div element props.
ListInvites.Title
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default title rendering |
size | enum | "3XL" | Typography size for the title |
weight | enum | "bold" | Typography weight |
type | enum | "heading" | Typography type |
color | enum | "low-emphasis" | Color theme for the title |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML span element props.
ListInvites.Action
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default action rendering |
direction | enum | "row" | Flex direction for action buttons |
alignItems | enum | "stretch" | Alignment of items in the container |
gapSize | enum | "S" | Gap between items in the container |
className | string | undefined | Additional CSS class name for styling |
ListInvites.Content
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default content rendering |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML div element props.
ListInvites.Loader
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Circular progress indicator | Custom loading indicator content |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML div element props.
ListInvites.Table
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional CSS class name for styling |
data | ListInvitesRowData[] | From context | Array of table data |
labels | TableLabels | Required | Labels object for table headers, actions, and messages |
dropdownMenuItems | (cell: ListInvitesRowData) => Array<DropDownMenuItems> | From context | Function to generate dropdown menu items |
dropdownMenuState | {openedDropdownMenuId: string} | From context | Currently opened dropdown menu |
setDropdownMenuState | ({openedDropdownMenuId: string}) => void | From context | Callback function when the opened dropdown menu changes |
emptyState | {icon?: IconType; message: string} | From context | Configuration for empty state |
isLoading | boolean | From context | Loading state |
onNavigate | (to: string) => void | From context | Navigation callback function |
pagination | {currentPage: number; onPageChange: (page: number) => void; totalPages: number} | From context | Pagination configuration |
rowHref | `(cell: ListInvitesRowData) => string | undefined | null` |
🔧 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {ListInvites} from '@nodeblocks/frontend-list-invites-block';
interface ListInvitesRowData {
id: string;
name: string;
email: string;
status: string;
}
interface CustomInviteTableProps {
invites: ListInvitesRowData[];
onRejectInvite: (inviteId: string) => void;
onInviteUser: () => void;
isTableLoading: boolean;
}
interface TableLabels {
emptyStateMessage: string;
actions: {
inviteUser: string;
};
headerRow: {
name: string;
email: string;
status: string;
};
rowActions: {
reject: string;
};
unsetDateMessage: string;
}
const InviteTableComponent = ({invites, onRejectInvite, onInviteUser, isTableLoading}: CustomInviteTableProps) => {
const tableLabels: TableLabels = {
emptyStateMessage: 'No invites available',
actions: {inviteUser: 'Send Invite'},
headerRow: {
name: 'Full Name',
email: 'Email Address',
status: 'Invite Status',
},
rowActions: {
reject: 'Reject Invitation',
},
unsetDateMessage: 'Date not set',
};
return (
<ListInvites
listInvitesTitle="Team Invitations"
labels={tableLabels}
isLoading={isTableLoading}
onNavigate={path => console.log('Navigate:', path)}
onClickAction={onInviteUser}
onItemReject={onRejectInvite}
data={invites}
rowHref={row => `/invites/${row.id}`}>
<ListInvites.Header />
<ListInvites.Content />
</ListInvites>
);
};
Built with ❤️ using React, TypeScript, and modern web standards.