Skip to content

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

PropTypeDefaultDescription
rowsany[][]Array of row data
columnsColumn[][]Column definitions
rowKeystring'id'Property used as unique key
loadingbooleanfalseShow loading spinner
featuresFeatures{}Feature toggles
paginationPaginationnullPagination configuration
visibleColumnsstring[]-Explicitly control visible columns
densebooleanfalseCompact row height
flatStylebooleanfalseRemove borders and shadows
stripedbooleantrueZebra striping in rows
selectableRows'single'|'multiple'|'none''multiple'Selection mode
selectOnRowClickbooleanfalseSelect row on click
noDataLabelstring'No data'Empty state message
selectedRowsstring[][]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

EventPayloadDescription
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:paginationPaginationPagination 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

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

DocBits Component Library