Skip to content

UnifiedTable

Alternative unified table implementation with a simplified feature set.

Overview

UnifiedTable is a lighter-weight alternative to DocBitsTable. It provides core table functionality with a simpler API for cases where you don't need all features.

Best for: Simpler tables with lighter bundle size

Key Features:

  • ✅ Sorting
  • ✅ Pagination
  • ✅ Row selection
  • ✅ Dark mode support
  • ✅ Simplified API

Comparison with DocBitsTable

FeatureDocBitsTableUnifiedTable
Sorting
Pagination
Row Selection
Filtering-
Bulk Actions-
Row Actions-
Column Resizing-
Dark Mode
Accessibility

When to use UnifiedTable:

  • Simpler data tables
  • Lighter bundle size is critical
  • Don't need bulk operations
  • Don't need column resizing

When to use DocBitsTable:

  • Full-featured tables
  • Complex interactions
  • Bulk operations needed
  • Maximum flexibility

Props

Same as DocBitsTable but with fewer features available.

Basic Usage

vue
<template>
  <UnifiedTable
    :rows="documents"
    :columns="columns"
    row-key="id"
    :features="{
      sorting: true,
      selection: true,
      pagination: true
    }"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import UnifiedTable from '@/components/Table/UnifiedTable.vue'

const columns = [
  { name: 'id', label: 'ID', field: 'id', sortable: true },
  { name: 'name', label: 'Name', field: 'name', sortable: true },
  { name: 'status', label: 'Status', field: 'status' }
]

const documents = ref([
  { id: 1, name: 'Document 1', status: 'Active' },
  { id: 2, name: 'Document 2', status: 'Archived' }
])
</script>

Real-World Example: Simple Invoice Table

This example demonstrates UnifiedTable with realistic invoice data, showing core features like sorting, pagination, and selection without advanced features.

Implementation

vue
<template>
  <div class="invoice-table-container">
    <div class="table-controls">
      <h2>Invoices</h2>
      <div class="control-actions">
        <button v-if="selectedRows.size > 0" class="btn export" @click="exportSelected">
          Export ({{ selectedRows.size }} selected)
        </button>
      </div>
    </div>

    <UnifiedTable
      :rows="invoices"
      :columns="columns"
      row-key="id"
      :page-size="5"
      :features="{
        sorting: true,
        selection: true,
        pagination: true
      }"
      @row-click="handleRowClick"
      @selection-change="handleSelectionChange"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import UnifiedTable from '@/components/Table/UnifiedTable.vue'

interface Invoice {
  id: string
  documentNumber: string
  vendor: string
  amount: number
  currency: string
  invoiceDate: string
  status: 'pending' | 'approved' | 'processed'
}

const columns = [
  { name: 'documentNumber', label: 'Invoice #', field: 'documentNumber', sortable: true },
  { name: 'vendor', label: 'Vendor', field: 'vendor', sortable: true },
  { name: 'amount', label: 'Amount', field: 'amount', sortable: true, align: 'right',
    format: (val: number, row: Invoice) => `${row.currency} ${val.toFixed(2)}` },
  { name: 'invoiceDate', label: 'Date', field: 'invoiceDate', sortable: true,
    format: (val: string) => new Date(val).toLocaleDateString() },
  { name: 'status', label: 'Status', field: 'status', sortable: true,
    format: (val: string) => val.charAt(0).toUpperCase() + val.slice(1) }
]

const invoices = ref<Invoice[]>([
  {
    id: 'INV-2024-001',
    documentNumber: 'INV-001234',
    vendor: 'Acme Corporation',
    amount: 1250.00,
    currency: 'USD',
    invoiceDate: '2024-01-15',
    status: 'pending'
  },
  {
    id: 'INV-2024-002',
    documentNumber: 'INV-001235',
    vendor: 'Global Supplies Inc',
    amount: 3750.50,
    currency: 'USD',
    invoiceDate: '2024-01-16',
    status: 'pending'
  },
  {
    id: 'INV-2024-003',
    documentNumber: 'RE-2024-789',
    vendor: 'Tech Solutions GmbH',
    amount: 2100.00,
    currency: 'EUR',
    invoiceDate: '2024-01-18',
    status: 'approved'
  },
  {
    id: 'INV-2024-004',
    documentNumber: 'INV-UK-445',
    vendor: 'British Office Ltd',
    amount: 890.00,
    currency: 'GBP',
    invoiceDate: '2024-01-20',
    status: 'pending'
  },
  {
    id: 'INV-2024-005',
    documentNumber: 'F-2024-1122',
    vendor: 'Consulting Partners SA',
    amount: 8500.00,
    currency: 'EUR',
    invoiceDate: '2024-01-22',
    status: 'processed'
  },
  {
    id: 'INV-2024-006',
    documentNumber: 'INV-2024-556',
    vendor: 'Cloud Services Corp',
    amount: 4200.00,
    currency: 'USD',
    invoiceDate: '2024-01-25',
    status: 'approved'
  },
  {
    id: 'INV-2024-007',
    documentNumber: 'BILL-7788',
    vendor: 'Utilities Company',
    amount: 650.25,
    currency: 'USD',
    invoiceDate: '2024-01-28',
    status: 'processed'
  },
  {
    id: 'INV-2024-008',
    documentNumber: 'INV-Q1-2024',
    vendor: 'Marketing Agency LLC',
    amount: 12000.00,
    currency: 'USD',
    invoiceDate: '2024-01-30',
    status: 'pending'
  }
]

const selectedRows = ref(new Set<string>())

function handleRowClick(row: Invoice) {
  console.log('Clicked row:', row)
}

function handleSelectionChange(selected: string[]) {
  selectedRows.value = new Set(selected)
}

function exportSelected() {
  const selected = Array.from(selectedRows.value)
  const data = invoices.value.filter(inv => selected.includes(inv.id))

  const csv = [
    ['Invoice #', 'Vendor', 'Amount', 'Date', 'Status'],
    ...data.map(inv => [
      inv.documentNumber,
      inv.vendor,
      `${inv.currency} ${inv.amount.toFixed(2)}`,
      new Date(inv.invoiceDate).toLocaleDateString(),
      inv.status
    ])
  ]
    .map(row => row.join(','))
    .join('\n')

  const blob = new Blob([csv], { type: 'text/csv' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = 'invoices.csv'
  a.click()
  URL.revokeObjectURL(url)
}
</script>

<style scoped>
.invoice-table-container {
  background: white;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid #e0e0e0;
}

.table-controls {
  padding: 20px;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.table-controls h2 {
  margin: 0;
  font-size: 1.25em;
}

.control-actions {
  display: flex;
  gap: 8px;
}

.btn {
  padding: 8px 16px;
  background: #2388AE;
  color: white;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.2s;
}

.btn:hover {
  background: #1a6a8a;
}

.btn.export {
  background: #34eea9;
}

.btn.export:hover {
  background: #2dd897;
}
</style>

What This Example Shows

  • Simple Feature Set: Only sorting, pagination, and selection - no bulk actions or row actions
  • Pagination: Built-in pagination with 5 rows per page
  • Sorting: Click column headers to sort by vendor, amount, or date
  • Selection: Select multiple invoices to export as CSV
  • Formatting: Currency formatting and date localization for different locales
  • Realistic Data: Multiple vendors, currencies (USD, EUR, GBP), and statuses
  • Export Functionality: Export selected invoices as CSV file
  • Lighter Weight: Simpler implementation perfect for straightforward data display use cases

Features Demonstrated

FeatureStatusDescription
SortingSort invoices by any column
PaginationDisplay 5 rows per page with navigation
Row SelectionSelect multiple rows, export selected
Data FormattingCurrency formatting with amounts
Status DisplayPending, approved, processed states
Bulk Actions-Not supported in UnifiedTable
Row Actions-Not supported in UnifiedTable

When to Use UnifiedTable vs DocBitsTable

Choose UnifiedTable for:

  • Simple read-only data display
  • Need to minimize bundle size
  • Only need basic sorting and pagination
  • No bulk operations required

Choose DocBitsTable for:

  • Need bulk operations (approve multiple, export batch)
  • Need per-row actions (view details, delete)
  • Need filtering and advanced searching
  • Need maximum flexibility and features

Performance

Slightly faster than DocBitsTable due to simpler implementation:

  • Smaller component size
  • Fewer features to manage
  • Faster initial render

Bundle Size

  • UnifiedTable: ~15KB (minified)
  • DocBitsTable: ~20KB (minified)

Migration from UnifiedTable to DocBitsTable

If you outgrow UnifiedTable, migrating to DocBitsTable is straightforward:

  1. Replace component import
  2. Add additional features to features object
  3. Handle new events if using bulk actions or row actions
vue
<!-- Before: UnifiedTable -->
<UnifiedTable
  :rows="documents"
  :columns="columns"
  :features="{ sorting: true, pagination: true }"
/>

<!-- After: DocBitsTable with all features -->
<DocBitsTable
  :rows="documents"
  :columns="columns"
  :features="{
    sorting: true,
    pagination: true,
    selection: true,
    bulkActions: true,
    rowActions: true
  }"
  @bulk-action="handleBulkAction"
  @row-action="handleRowAction"
/>

Browser Support

Supported in all modern browsers:

  • Chrome 88+
  • Firefox 78+
  • Safari 14+
  • Edge 88+

Source Code

  • Component: src/components/Table/UnifiedTable.vue (656 lines)

Changelog

v1.0.0 (2025-12-18)

  • Initial release
  • Simplified table implementation
  • Core features only
  • Lighter bundle size

DocBits Component Library