A PDF generation library for Node.js with comprehensive text, graphics, and form support
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Structured table creation with comprehensive layout and styling options for professional document formatting.
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'
}
});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();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();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' }
}
]
});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);
});// 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 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);// 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
});// 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
});// 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