CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pdfkit

A PDF generation library for Node.js with comprehensive text, graphics, and form support

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

tables.mddocs/

Tables

Structured table creation with comprehensive layout and styling options for professional document formatting.

Capabilities

Table Creation

Create structured tables with flexible data input and extensive styling options.

/**
 * Create a new table
 * @param options - Table configuration options
 * @returns PDFTable instance for adding rows
 */
table(options?: TableOptions): PDFTable;

interface TableOptions {
  /** Table data as array of arrays or objects */
  data?: any[][];
  /** Column headers */
  headers?: string[];
  /** Column widths (points or percentages) */
  columnWidths?: (number | string)[];
  /** Table width */
  width?: number;
  /** Table position */
  x?: number;
  y?: number;
  /** Cell padding */
  padding?: number | [number, number] | [number, number, number, number];
  /** Row height */
  rowHeight?: number;
  /** Header row styling */
  headerStyle?: CellStyle;
  /** Data row styling */
  rowStyle?: CellStyle;
  /** Alternating row styling */
  alternatingRowStyle?: CellStyle;
  /** Border styling */
  borderStyle?: BorderStyle;
  /** Text alignment */
  align?: 'left' | 'center' | 'right';
  /** Vertical alignment */
  valign?: 'top' | 'center' | 'bottom';
}

interface CellStyle {
  fontSize?: number;
  font?: string;
  fillColor?: ColorValue;
  textColor?: ColorValue;
  padding?: number | [number, number] | [number, number, number, number];
}

interface BorderStyle {
  width?: number;
  color?: ColorValue;
  style?: 'solid' | 'dashed' | 'dotted';
}

Usage Examples:

// Basic table creation
const table = doc.table({
  headers: ['Name', 'Age', 'City'],
  data: [
    ['Alice', '25', 'New York'],
    ['Bob', '30', 'Los Angeles'],
    ['Charlie', '35', 'Chicago']
  ]
});

// Table with custom styling
const styledTable = doc.table({
  headers: ['Product', 'Price', 'Quantity', 'Total'],
  columnWidths: [200, 80, 80, 100],
  headerStyle: {
    fontSize: 12,
    font: 'Helvetica-Bold',
    fillColor: '#f0f0f0',
    textColor: '#000000'
  },
  rowStyle: {
    fontSize: 10,
    padding: 5
  },
  borderStyle: {
    width: 1,
    color: '#cccccc'
  }
});

Table Instance Methods

Build tables row by row with fine control over content and styling.

interface PDFTable {
  /**
   * Add a row to the table
   * @param data - Row data as array
   * @param isLastRow - Whether this is the last row
   * @returns Table instance for chaining, or document if last row
   */
  row(data: any[], isLastRow?: boolean): PDFTable | PDFDocument;
  
  /**
   * End table construction
   * @returns Document instance for chaining
   */
  end(): PDFDocument;
  
  /** Current table position */
  x: number;
  y: number;
  
  /** Table dimensions */
  width: number;
  height: number;
}

Usage Examples:

// Build table row by row
const table = doc.table({
  headers: ['Item', 'Description', 'Amount'],
  columnWidths: [100, 250, 100]
});

// Add data rows
table.row(['Item 1', 'First item description', '$10.00']);
table.row(['Item 2', 'Second item description', '$15.50']);
table.row(['Item 3', 'Third item description', '$8.75']);

// Add total row with different styling
table.row(['', 'Total:', '$34.25'], true);

// End table construction
table.end();

Advanced Table Features

Create complex tables with merged cells, nested content, and conditional formatting.

interface AdvancedTableOptions extends TableOptions {
  /** Enable automatic page breaks */
  pageBreak?: boolean;
  /** Header repetition on new pages */
  repeatHeader?: boolean;
  /** Cell merging specifications */
  mergedCells?: MergedCell[];
  /** Conditional row formatting */
  conditionalFormatting?: ConditionalFormat[];
}

interface MergedCell {
  startRow: number;
  endRow: number;
  startCol: number;
  endCol: number;
  content: string;
  style?: CellStyle;
}

interface ConditionalFormat {
  condition: (rowData: any[], rowIndex: number) => boolean;
  style: CellStyle;
}

Usage Examples:

// Table with page breaks and header repetition
const reportTable = doc.table({
  headers: ['Date', 'Transaction', 'Debit', 'Credit', 'Balance'],
  pageBreak: true,
  repeatHeader: true,
  headerStyle: {
    fontSize: 10,
    font: 'Helvetica-Bold',
    fillColor: '#d0d0d0'
  },
  conditionalFormatting: [
    {
      condition: (rowData) => parseFloat(rowData[4]) < 0,
      style: { textColor: 'red' }
    }
  ]
});

// Add many rows (will break across pages)
for (let i = 0; i < 100; i++) {
  reportTable.row([
    `2024-01-${String(i + 1).padStart(2, '0')}`,
    `Transaction ${i + 1}`,
    i % 3 === 0 ? '$100.00' : '',
    i % 3 !== 0 ? '$50.00' : '',
    `$${(1000 + i * 25).toFixed(2)}`
  ]);
}

reportTable.end();

Data-Driven Tables

Create tables from structured data sources with automatic formatting.

Usage Examples:

// Table from object array
const salesData = [
  { product: 'Laptop', region: 'North', sales: 1250, target: 1000 },
  { product: 'Mouse', region: 'South', sales: 890, target: 900 },
  { product: 'Keyboard', region: 'East', sales: 1100, target: 1200 },
  { product: 'Monitor', region: 'West', sales: 750, target: 800 }
];

const salesTable = doc.table({
  headers: ['Product', 'Region', 'Sales', 'Target', 'Performance'],
  columnWidths: [100, 80, 80, 80, 100],
  data: salesData.map(item => [
    item.product,
    item.region,
    `$${item.sales}`,
    `$${item.target}`,
    `${((item.sales / item.target) * 100).toFixed(1)}%`
  ]),
  conditionalFormatting: [
    {
      condition: (rowData) => {
        const performance = parseFloat(rowData[4]);
        return performance >= 100;
      },
      style: { fillColor: '#e8f5e8', textColor: '#2e7d32' }
    },
    {
      condition: (rowData) => {
        const performance = parseFloat(rowData[4]);
        return performance < 90;
      },
      style: { fillColor: '#ffebee', textColor: '#c62828' }
    }
  ]
});

Financial Tables

Specialized formatting for financial and numerical data.

Usage Examples:

// Financial report table
const financialTable = doc.table({
  headers: ['Account', 'Q1', 'Q2', 'Q3', 'Q4', 'Total'],
  columnWidths: [150, 80, 80, 80, 80, 100],
  headerStyle: {
    fontSize: 11,
    font: 'Helvetica-Bold',
    fillColor: '#f5f5f5',
    textColor: '#333333'
  },
  rowStyle: {
    fontSize: 10,
    padding: [3, 8, 3, 8]
  },
  align: 'right' // Right-align numbers
});

const accounts = [
  ['Revenue', 125000, 132000, 145000, 155000, 557000],
  ['Cost of Goods', -45000, -48000, -52000, -55000, -200000],
  ['Gross Profit', 80000, 84000, 93000, 100000, 357000],
  ['Operating Expenses', -35000, -37000, -40000, -42000, -154000],
  ['Net Income', 45000, 47000, 53000, 58000, 203000]
];

accounts.forEach((account, index) => {
  const isTotal = account[0] === 'Net Income';
  const formattedRow = [
    account[0],
    ...account.slice(1).map(val => 
      val < 0 ? `(${Math.abs(val).toLocaleString()})` : val.toLocaleString()
    )
  ];
  
  financialTable.row(formattedRow, index === accounts.length - 1);
});

Table Layout Patterns

Multi-Section Reports

// Create report with multiple table sections
doc.fontSize(16).text('Quarterly Sales Report', 100, 100);

// Summary table
doc.fontSize(12).text('Executive Summary', 100, 150);
const summaryTable = doc.table({
  x: 100,
  y: 170,
  headers: ['Metric', 'Q4 2023', 'Q1 2024', 'Change'],
  data: [
    ['Total Sales', '$2.1M', '$2.3M', '+9.5%'],
    ['New Customers', '1,250', '1,420', '+13.6%'],
    ['Retention Rate', '89%', '92%', '+3%']
  ]
});
summaryTable.end();

// Detailed breakdown
doc.fontSize(12).text('Regional Breakdown', 100, 280);
const regionalTable = doc.table({
  x: 100,
  y: 300,
  headers: ['Region', 'Sales', 'Growth', 'Market Share'],
  data: [
    ['North America', '$1.2M', '+12%', '52%'],
    ['Europe', '$750K', '+8%', '33%'],
    ['Asia Pacific', '$350K', '+15%', '15%']
  ]
});
regionalTable.end();

Invoice Tables

// Invoice line items table
const invoiceTable = doc.table({
  headers: ['Description', 'Qty', 'Rate', 'Amount'],
  columnWidths: [250, 60, 80, 100],
  headerStyle: {
    fontSize: 11,
    font: 'Helvetica-Bold',
    fillColor: '#f8f9fa'
  }
});

const lineItems = [
  ['Web Development Services', '40', '$125.00', '$5,000.00'],
  ['UI/UX Design', '20', '$100.00', '$2,000.00'],
  ['Project Management', '10', '$150.00', '$1,500.00']
];

lineItems.forEach(item => {
  invoiceTable.row(item);
});

// Totals section
invoiceTable.row(['', '', 'Subtotal:', '$8,500.00']);
invoiceTable.row(['', '', 'Tax (8.5%):', '$722.50']);
invoiceTable.row(['', '', 'Total:', '$9,222.50'], true);

Best Practices

Performance Optimization

// Pre-calculate table dimensions
const tableWidth = 500;
const columnCount = 4;
const columnWidth = tableWidth / columnCount;

// Use consistent column widths
const optimizedTable = doc.table({
  columnWidths: Array(columnCount).fill(columnWidth),
  width: tableWidth
});

Responsive Design

// Adjust table based on page size
const pageWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
const table = doc.table({
  width: Math.min(pageWidth, 600), // Don't exceed page width
  columnWidths: ['30%', '40%', '30%'] // Use percentages for flexibility
});

Data Validation

// Validate data before table creation
function createSafeTable(data, headers) {
  // Ensure all rows have same column count
  const columnCount = headers.length;
  const validatedData = data.map(row => {
    const paddedRow = [...row];
    while (paddedRow.length < columnCount) {
      paddedRow.push('');
    }
    return paddedRow.slice(0, columnCount);
  });
  
  return doc.table({
    headers,
    data: validatedData
  });
}

Install with Tessl CLI

npx tessl i tessl/npm-pdfkit

docs

accessibility-features.md

attachments.md

color-management.md

document-management.md

font-management.md

image-handling.md

index.md

interactive-elements.md

outline.md

tables.md

text-rendering.md

vector-graphics.md

tile.json