DocBitsTable
The main unified table component with all features - sorting, filtering, selection, pagination, and bulk actions.
Overview
DocBitsTable is the primary table component for DocBits applications. It integrates all other table components and provides a feature-rich, enterprise-grade table with minimal setup required.
Best for: Complete data tables with all features enabled
Key Features:
- ✅ Sorting with visual indicators
- ✅ Filtering and search
- ✅ Pagination with configurable page sizes
- ✅ Row selection (single/multi-select)
- ✅ Bulk action menu
- ✅ Per-row action menus
- ✅ Resizable columns
- ✅ Dark mode support
- ✅ Full accessibility
Props
| Prop | Type | Default | Description |
|---|---|---|---|
rows | any[] | [] | Array of row data |
columns | Column[] | [] | Column definitions |
rowKey | string | 'id' | Property used as unique key |
loading | boolean | false | Show loading spinner |
features | Features | {} | Feature toggles |
pagination | Pagination | null | Pagination configuration |
visibleColumns | string[] | - | Explicitly control visible columns |
dense | boolean | false | Compact row height |
flatStyle | boolean | false | Remove borders and shadows |
striped | boolean | true | Zebra striping in rows |
selectableRows | 'single'|'multiple'|'none' | 'multiple' | Selection mode |
selectOnRowClick | boolean | false | Select row on click |
noDataLabel | string | 'No data' | Empty state message |
selectedRows | string[] | [] | Currently selected row IDs |
Column Definition
typescript
interface Column {
name: string // Unique column identifier
label: string // Display label
field: string | ((row) => any) // Data field accessor
sortable?: boolean // Enable sorting
align?: 'left' | 'right' | 'center'
style?: string | object // Cell styles
headerStyle?: string | object
classes?: string | string[]
headerClasses?: string | string[]
format?: (val, row) => string // Value formatter
resizable?: boolean // Allow column resize
width?: number | string // Fixed width
}Features Configuration
typescript
interface Features {
sorting?: boolean // Enable column sorting
filtering?: boolean // Enable filter UI
selection?: boolean // Enable row checkboxes
bulkActions?: boolean // Show bulk action FAB
rowActions?: boolean // Show per-row menu
resizable?: boolean // Allow column resizing
pagination?: boolean // Show pagination
}Events
| Event | Payload | Description |
|---|---|---|
row-click | { row, rowIndex, event } | Row clicked |
selection-change | { selected: Set } | Selection changed |
bulk-action | { action, selectedIds } | Bulk action triggered |
row-action | { action, rowId, row } | Row action triggered |
update:pagination | Pagination | Pagination state changed |
Basic Usage
vue
<template>
<DocBitsTable
:rows="documents"
:columns="columns"
row-key="id"
:features="{
sorting: true,
selection: true,
pagination: true,
bulkActions: true,
rowActions: true
}"
@row-click="handleRowClick"
@selection-change="handleSelection"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import DocBitsTable from '@/components/Table/DocBitsTable.vue'
const columns = [
{
name: 'id',
label: 'ID',
field: 'id',
sortable: true,
width: 80
},
{
name: 'name',
label: 'Document',
field: 'name',
sortable: true
},
{
name: 'status',
label: 'Status',
field: 'status',
format: (val) => val.toUpperCase()
}
]
const documents = ref([
{ id: 1, name: 'Invoice_001.pdf', status: 'processed' },
{ id: 2, name: 'Receipt_001.pdf', status: 'pending' }
])
function handleRowClick({ row }: { row: any }) {
console.log('Clicked row:', row)
}
function handleSelection({ selected }: { selected: Set<string> }) {
console.log('Selected rows:', Array.from(selected))
}
</script>Server-Side Data Loading
vue
<script setup lang="ts">
const loading = ref(false)
const rows = ref([])
const pagination = ref({
page: 1,
rowsPerPage: 10,
rowsNumber: 0
})
async function onRequest({ pagination: newPag }) {
loading.value = true
try {
const response = await fetch('/api/documents', {
params: {
page: newPag.page,
limit: newPag.rowsPerPage
}
})
const data = await response.json()
rows.value = data.items
pagination.value = {
...newPag,
rowsNumber: data.total
}
} finally {
loading.value = false
}
}
</script>Custom Cell Rendering
vue
<template>
<DocBitsTable :rows="rows" :columns="columns">
<template #body-cell-status="{ row }">
<span class="status-badge" :class="`status-${row.status}`">
{{ row.status }}
</span>
</template>
</DocBitsTable>
</template>
<style scoped>
.status-badge {
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-processed {
background: var(--docbits-positive);
color: white;
}
.status-pending {
background: var(--docbits-warning);
color: #000;
}
</style>Real-World Example: Complete Invoice Processing Table
This example shows a full-featured invoice management table with all DocBitsTable capabilities.
Sample Invoice Data (10 rows)
typescript
const invoices = [
{
id: 'INV-2024-001',
documentNumber: 'INV-001234',
vendor: 'Acme Corporation',
vendorAddress: '123 Business Park, New York, NY 10001',
amount: 1250.00,
currency: 'USD',
invoiceDate: '2024-01-15',
dueDate: '2024-02-15',
status: 'pending',
assignee: 'john.doe@company.com',
extractionConfidence: 0.98,
paymentTerms: 'Net 30',
taxAmount: 125.00
},
{
id: 'INV-2024-002',
documentNumber: 'INV-001235',
vendor: 'Global Supplies Inc',
vendorAddress: '456 Industrial Way, Chicago, IL 60601',
amount: 3750.50,
currency: 'USD',
invoiceDate: '2024-01-16',
dueDate: '2024-02-16',
status: 'approved',
assignee: 'jane.smith@company.com',
extractionConfidence: 0.95,
paymentTerms: 'Net 45',
taxAmount: 375.05
},
{
id: 'INV-2024-003',
documentNumber: 'RE-2024-789',
vendor: 'Tech Solutions GmbH',
vendorAddress: 'Hauptstraße 1, 10115 Berlin, Germany',
amount: 2100.00,
currency: 'EUR',
invoiceDate: '2024-01-18',
dueDate: '2024-02-18',
status: 'processed',
assignee: 'mike.johnson@company.com',
extractionConfidence: 0.97,
paymentTerms: 'Net 30',
taxAmount: 399.00
},
{
id: 'INV-2024-004',
documentNumber: 'INV-UK-445',
vendor: 'British Office Ltd',
vendorAddress: '789 Oxford Street, London W1D 2HG, UK',
amount: 890.00,
currency: 'GBP',
invoiceDate: '2024-01-20',
dueDate: '2024-03-20',
status: 'rejected',
assignee: 'sarah.williams@company.com',
extractionConfidence: 0.89,
paymentTerms: 'Net 60',
taxAmount: 178.00
},
{
id: 'INV-2024-005',
documentNumber: 'F-2024-1122',
vendor: 'Consulting Partners SA',
vendorAddress: 'Rue de la Paix 45, 75002 Paris, France',
amount: 8500.00,
currency: 'EUR',
invoiceDate: '2024-01-22',
dueDate: '2024-02-22',
status: 'pending',
assignee: 'pierre.dubois@company.com',
extractionConfidence: 0.93,
paymentTerms: 'Net 30',
taxAmount: 1700.00
},
{
id: 'INV-2024-006',
documentNumber: 'INV-2024-556',
vendor: 'Cloud Services Corp',
vendorAddress: '321 Tech Drive, San Francisco, CA 94105',
amount: 4200.00,
currency: 'USD',
invoiceDate: '2024-01-25',
dueDate: '2024-02-25',
status: 'approved',
assignee: 'john.doe@company.com',
extractionConfidence: 0.99,
paymentTerms: 'Net 15',
taxAmount: 420.00
},
{
id: 'INV-2024-007',
documentNumber: 'BILL-7788',
vendor: 'Utilities Company',
vendorAddress: '555 Power Street, Boston, MA 02101',
amount: 650.25,
currency: 'USD',
invoiceDate: '2024-01-28',
dueDate: '2024-02-15',
status: 'processed',
assignee: 'accounts@company.com',
extractionConfidence: 0.96,
paymentTerms: 'Due on receipt',
taxAmount: 65.03
},
{
id: 'INV-2024-008',
documentNumber: 'INV-Q1-2024',
vendor: 'Marketing Agency LLC',
vendorAddress: '999 Creative Blvd, Austin, TX 78701',
amount: 12000.00,
currency: 'USD',
invoiceDate: '2024-01-30',
dueDate: '2024-03-01',
status: 'pending',
assignee: 'marketing@company.com',
extractionConfidence: 0.91,
paymentTerms: 'Net 30',
taxAmount: 1200.00
},
{
id: 'INV-2024-009',
documentNumber: 'INV-SPARES-01',
vendor: 'Industrial Spares Ltd',
vendorAddress: '234 Commerce Street, Philadelphia, PA 19103',
amount: 2750.00,
currency: 'USD',
invoiceDate: '2024-02-01',
dueDate: '2024-03-01',
status: 'approved',
assignee: 'john.doe@company.com',
extractionConfidence: 0.94,
paymentTerms: 'Net 30',
taxAmount: 275.00
},
{
id: 'INV-2024-010',
documentNumber: 'INV-MNT-002',
vendor: 'Maintenance Services Inc',
vendorAddress: '567 Service Road, Houston, TX 77001',
amount: 1800.00,
currency: 'USD',
invoiceDate: '2024-02-02',
dueDate: '2024-03-02',
status: 'pending',
assignee: 'jane.smith@company.com',
extractionConfidence: 0.92,
paymentTerms: 'Net 30',
taxAmount: 180.00
}
]Complete Column Configuration
typescript
const invoiceColumns = [
{
name: 'documentNumber',
label: 'Invoice #',
field: 'documentNumber',
sortable: true,
align: 'left',
style: 'width: 140px'
},
{
name: 'vendor',
label: 'Vendor',
field: 'vendor',
sortable: true,
align: 'left'
},
{
name: 'amount',
label: 'Amount',
field: 'amount',
sortable: true,
align: 'right',
format: (val, row) => `${row.currency} ${val.toFixed(2)}`
},
{
name: 'invoiceDate',
label: 'Invoice Date',
field: 'invoiceDate',
sortable: true,
format: (val) => new Date(val).toLocaleDateString()
},
{
name: 'dueDate',
label: 'Due Date',
field: 'dueDate',
sortable: true,
format: (val) => new Date(val).toLocaleDateString()
},
{
name: 'status',
label: 'Status',
field: 'status',
sortable: true,
format: (val) => val.replace('_', ' ').toUpperCase()
},
{
name: 'assignee',
label: 'Assigned To',
field: 'assignee',
sortable: true
},
{
name: 'confidence',
label: 'Confidence',
field: 'extractionConfidence',
sortable: true,
align: 'right',
format: (val) => `${(val * 100).toFixed(0)}%`
}
]Complete Implementation with All Features
vue
<template>
<DocBitsTable
:rows="invoiceRows"
:columns="invoiceColumns"
row-key="id"
:loading="loading"
:pagination.sync="pagination"
:features="{
sorting: true,
selection: true,
bulkActions: true,
rowActions: true,
pagination: true
}"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
@bulk-action="handleBulkAction"
@row-action="handleRowAction"
@update:pagination="handlePaginationChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import DocBitsTable from '@/components/Table/DocBitsTable.vue'
const loading = ref(false)
const invoiceRows = ref(invoices)
const pagination = ref({
page: 1,
rowsPerPage: 10,
rowsNumber: 10
})
function handleRowClick({ row }) {
console.log('Row clicked:', row.documentNumber)
// Navigate to invoice detail view
}
function handleSelectionChange({ selected }) {
console.log('Selected invoices:', selected.size)
}
function handleBulkAction({ action, selectedIds }) {
console.log(`Bulk action: ${action} for invoices:`, selectedIds)
// Handle bulk export, delete, approve, etc.
}
function handleRowAction({ action, rowId, row }) {
console.log(`Row action: ${action} for invoice ${rowId}`)
// Handle individual actions
}
function handlePaginationChange(newPagination) {
pagination.value = newPagination
}
</script>What This Example Demonstrates
- Sorting: Sort invoices by amount, date, vendor, or status
- Selection: Select multiple invoices for bulk actions
- Pagination: Navigate through paginated results
- Bulk Actions: Export, delete, or approve multiple invoices
- Row Actions: Per-row view, edit, or delete options
- Formatting: Currency, dates, and percentage formatting
- Status Tracking: Visual indication of invoice approval status
- Confidence Scores: OCR extraction confidence percentages
Real-World Example: Document Processing Queue
This example shows a document queue table tracking processing status.
Sample Document Data (10 rows)
typescript
const documents = [
{ id: 'DOC-2024-001', fileName: 'invoice_acme_jan2024.pdf', documentType: 'Invoice', uploadDate: '2024-01-15T10:30:00Z', pages: 3, processingStatus: 'completed', ocrConfidence: 0.96, extractedFields: 15, assignedTo: 'system' },
{ id: 'DOC-2024-002', fileName: 'po_order_2024001.pdf', documentType: 'PO', uploadDate: '2024-01-15T11:00:00Z', pages: 2, processingStatus: 'completed', ocrConfidence: 0.98, extractedFields: 12, assignedTo: 'system' },
{ id: 'DOC-2024-003', fileName: 'receipt_starbucks_jan.pdf', documentType: 'Receipt', uploadDate: '2024-01-15T14:30:00Z', pages: 1, processingStatus: 'processing', ocrConfidence: 0.92, extractedFields: 8, assignedTo: 'system' },
{ id: 'DOC-2024-004', fileName: 'contract_legal_2024.pdf', documentType: 'Contract', uploadDate: '2024-01-16T09:00:00Z', pages: 8, processingStatus: 'processing', ocrConfidence: 0.85, extractedFields: 24, assignedTo: 'ocr2' },
{ id: 'DOC-2024-005', fileName: 'invoice_vendor_feb.pdf', documentType: 'Invoice', uploadDate: '2024-01-16T13:15:00Z', pages: 4, processingStatus: 'queued', ocrConfidence: 0.00, extractedFields: 0, assignedTo: 'queue' },
{ id: 'DOC-2024-006', fileName: 'receipt_office_depot.pdf', documentType: 'Receipt', uploadDate: '2024-01-17T10:45:00Z', pages: 1, processingStatus: 'completed', ocrConfidence: 0.94, extractedFields: 7, assignedTo: 'system' },
{ id: 'DOC-2024-007', fileName: 'po_request_2024002.pdf', documentType: 'PO', uploadDate: '2024-01-17T15:20:00Z', pages: 3, processingStatus: 'processing', ocrConfidence: 0.89, extractedFields: 10, assignedTo: 'ocr2' },
{ id: 'DOC-2024-008', fileName: 'invoice_large_contract.pdf', documentType: 'Invoice', uploadDate: '2024-01-18T08:30:00Z', pages: 12, processingStatus: 'failed', ocrConfidence: 0.00, extractedFields: 0, assignedTo: 'system' },
{ id: 'DOC-2024-009', fileName: 'receipt_hotel_conference.pdf', documentType: 'Receipt', uploadDate: '2024-01-18T16:00:00Z', pages: 2, processingStatus: 'queued', ocrConfidence: 0.00, extractedFields: 0, assignedTo: 'queue' },
{ id: 'DOC-2024-010', fileName: 'po_critical_order.pdf', documentType: 'PO', uploadDate: '2024-01-19T12:30:00Z', pages: 5, processingStatus: 'completed', ocrConfidence: 0.97, extractedFields: 14, assignedTo: 'system' }
]Document Queue Implementation
vue
<template>
<DocBitsTable
:rows="documentQueue"
:columns="documentColumns"
row-key="id"
:loading="loading"
:features="{
sorting: true,
selection: true,
bulkActions: true,
pagination: true
}"
@selection-change="handleDocumentSelection"
@bulk-action="handleDocumentBulkAction"
/>
</template>
<script setup lang="ts">
const loading = ref(false)
const documentQueue = ref(documents)
const documentColumns = [
{ name: 'fileName', label: 'File Name', field: 'fileName', sortable: true },
{ name: 'documentType', label: 'Type', field: 'documentType', sortable: true },
{ name: 'uploadDate', label: 'Uploaded', field: 'uploadDate', sortable: true,
format: (val) => new Date(val).toLocaleString() },
{ name: 'pages', label: 'Pages', field: 'pages', sortable: true, align: 'center' },
{ name: 'processingStatus', label: 'Status', field: 'processingStatus', sortable: true },
{ name: 'ocrConfidence', label: 'OCR Confidence', field: 'ocrConfidence', sortable: true, align: 'right',
format: (val) => val > 0 ? `${(val * 100).toFixed(0)}%` : 'Pending' },
{ name: 'extractedFields', label: 'Fields', field: 'extractedFields', sortable: true, align: 'center' }
]
</script>What This Example Demonstrates
- Document Processing States: Track queued, processing, completed, and failed documents
- OCR Confidence: Display extraction confidence percentages
- Bulk Processing: Select and reprocess failed documents
- Multi-format Support: Handle invoices, POs, receipts, contracts
- Progress Tracking: Monitor extracted fields vs. total pages
- Queue Management: Prioritize documents for processing
Real-World Example: Purchase Order Matching
This example shows PO matching with invoice correlation.
typescript
const purchaseOrders = [
{ id: 'PO-2024-001', poNumber: 'PO-123456', supplier: 'Acme Corp', totalAmount: 5000.00, currency: 'USD', orderDate: '2024-01-10', deliveryDate: '2024-02-10', status: 'pending', lineItems: 5, matchedInvoices: 0 },
{ id: 'PO-2024-002', poNumber: 'PO-123457', supplier: 'Global Supplies Inc', totalAmount: 12500.00, currency: 'USD', orderDate: '2024-01-12', deliveryDate: '2024-02-12', status: 'confirmed', lineItems: 8, matchedInvoices: 2 },
{ id: 'PO-2024-003', poNumber: 'PO-EU-789', supplier: 'Tech Solutions GmbH', totalAmount: 8750.00, currency: 'EUR', orderDate: '2024-01-15', deliveryDate: '2024-02-15', status: 'delivered', lineItems: 6, matchedInvoices: 6 },
{ id: 'PO-2024-004', poNumber: 'PO-UK-445', supplier: 'British Office Ltd', totalAmount: 3200.00, currency: 'GBP', orderDate: '2024-01-18', deliveryDate: '2024-02-18', status: 'cancelled', lineItems: 4, matchedInvoices: 1 },
{ id: 'PO-2024-005', poNumber: 'PO-FR-2024', supplier: 'Consulting Partners SA', totalAmount: 15000.00, currency: 'EUR', orderDate: '2024-01-20', deliveryDate: '2024-03-01', status: 'pending', lineItems: 10, matchedInvoices: 0 },
{ id: 'PO-2024-006', poNumber: 'PO-CLOUD-001', supplier: 'Cloud Services Corp', totalAmount: 6000.00, currency: 'USD', orderDate: '2024-01-22', deliveryDate: '2024-02-22', status: 'delivered', lineItems: 3, matchedInvoices: 3 },
{ id: 'PO-2024-007', poNumber: 'PO-UTIL-02', supplier: 'Utilities Company', totalAmount: 2100.00, currency: 'USD', orderDate: '2024-01-25', deliveryDate: '2024-02-15', status: 'confirmed', lineItems: 2, matchedInvoices: 1 },
{ id: 'PO-2024-008', poNumber: 'PO-MKT-Q1', supplier: 'Marketing Agency LLC', totalAmount: 20000.00, currency: 'USD', orderDate: '2024-01-28', deliveryDate: '2024-03-15', status: 'pending', lineItems: 15, matchedInvoices: 0 }
]
const poColumns = [
{ name: 'poNumber', label: 'PO #', field: 'poNumber', sortable: true },
{ name: 'supplier', label: 'Supplier', field: 'supplier', sortable: true },
{ name: 'totalAmount', label: 'Total', field: 'totalAmount', sortable: true, align: 'right',
format: (val, row) => `${row.currency} ${val.toFixed(2)}` },
{ name: 'orderDate', label: 'Order Date', field: 'orderDate', sortable: true,
format: (val) => new Date(val).toLocaleDateString() },
{ name: 'status', label: 'Status', field: 'status', sortable: true },
{ name: 'lineItems', label: 'Line Items', field: 'lineItems', sortable: true, align: 'center' },
{ name: 'matchedInvoices', label: 'Matched', field: 'matchedInvoices', sortable: true, align: 'center' }
]Accessibility
- ✅ Full keyboard navigation (Tab, Arrow keys, Space, Enter)
- ✅ Proper ARIA labels and roles
- ✅ Screen reader support
- ✅ Focus management
- ✅ WCAG 2.1 AA color contrast
Testing
typescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import DocBitsTable from './DocBitsTable.vue'
describe('DocBitsTable', () => {
const columns = [
{ name: 'id', label: 'ID', field: 'id' },
{ name: 'name', label: 'Name', field: 'name' }
]
const rows = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
]
it('renders table with data', () => {
const wrapper = mount(DocBitsTable, {
props: { rows, columns, rowKey: 'id' }
})
expect(wrapper.findAll('tr').length).toBe(3) // header + 2 rows
})
it('emits row-click event', async () => {
const wrapper = mount(DocBitsTable, {
props: { rows, columns, rowKey: 'id' }
})
await wrapper.find('tbody tr').trigger('click')
expect(wrapper.emitted('row-click')).toBeTruthy()
})
})Performance
- Virtual scrolling for 1000+ rows
- Debounced operations (300ms)
- Efficient event handling
- Minimal re-renders
Benchmark: 10,000 rows render in <100ms with virtual scrolling
Related Components
- UnifiedTable - Simplified alternative
- ColumnOrderBy - Sorting
- RowSelectionCheckbox - Selection
- BulkActionsMenu - Bulk operations
- RowActionsMenu - Row actions
Source Code
- Component:
src/components/Table/DocBitsTable.vue(664 lines)
Changelog
v1.0.0 (2025-12-18)
- Initial release
- Complete feature set
- Full accessibility
- Dark mode support