The reliable way to make a jsPDF table cleaner is to make its layout explicit: define semantic data keys, choose a theme, set section and column styles, enable deliberate wrapping, and configure pagination separately. jsPDF-AutoTable accepts HTML tables or JavaScript data and works with jsPDF through npm, downloaded files, or a CDN. The example below uses the modular npm API and shows the settings that prevent clipped text, inconsistent colors, and broken page breaks.
Install jsPDF and AutoTable
Install both packages in a JavaScript project:
npm install jspdf jspdf-autotable
Then import them:
import { jsPDF } from 'jspdf'
import { autoTable } from 'jspdf-autotable'
The plugin can also be loaded from downloaded distribution files or a CDN. You may pass an existing HTML table to AutoTable, or provide columns and body arrays. JavaScript data is generally easier to maintain because column styles can target stable semantic keys.
A complete tidy-table configuration
This runnable example controls typography, spacing, widths, alignment, wrapping, borders, and pagination in one place:
import { jsPDF } from 'jspdf'
import { autoTable } from 'jspdf-autotable'
const rows = [
{ item: 'API subscription', qty: 1, notes: 'Renews monthly; cancel before the renewal date.' },
{ item: 'Implementation support', qty: 3, notes: 'Includes setup, testing, and hand-off documentation.' },
{ item: 'Training session', qty: 2, notes: 'Remote session with downloadable reference material.' }
]
const doc = new jsPDF()
autoTable(doc, {
columns: [
{ header: 'Item', dataKey: 'item' },
{ header: 'Qty', dataKey: 'qty' },
{ header: 'Notes', dataKey: 'notes' }
],
body: rows,
theme: 'striped',
styles: {
font: 'helvetica',
fontSize: 9,
cellPadding: 4,
overflow: 'linebreak',
valign: 'top',
lineColor: [210, 214, 220],
lineWidth: 0.2
},
headStyles: {
fillColor: [35, 64, 90],
textColor: 255,
fontStyle: 'bold',
halign: 'left'
},
alternateRowStyles: {
fillColor: [245, 247, 250]
},
columnStyles: {
item: { cellWidth: 45 },
qty: { cellWidth: 18, halign: 'right' },
notes: { cellWidth: 'wrap' }
},
margin: { top: 24, right: 18, bottom: 24, left: 18 },
showHead: 'everyPage',
pageBreak: 'auto',
rowPageBreak: 'avoid'
})
doc.save('table.pdf')
The illustrative RGB value must be numeric; for example, the blue header uses [35, 64, 90]. Adjust widths to your page orientation and content rather than relying on automatic sizing for every column.
#1 Best Overall
- EDIT text, images & designs in PDF documents. ORGANIZE PDFs. Convert PDFs to Word, Excel & ePub.
- READ and Comment PDFs – Intuitive reading modes & document commenting and mark up.
- CREATE, COMBINE, SCAN and COMPRESS PDFs
- FILL forms & Digitally Sign PDFs. PROTECT and Encrypt PDFs
- LIFETIME License for 1 Windows PC or Laptop. 5GB MobiDrive Cloud Storage Included.
How AutoTable style precedence works
When multiple rules set the same property, AutoTable applies them from broadest to most specific:
- Theme establishes the base look.
- styles applies to table cells generally.
- Section styles such as
headStyles,bodyStyles, andfootStylesoverride the general rules for that section. - alternateRowStyles changes alternating body rows.
- columnStyles applies per-column settings.
Cell definitions and hook callbacks can make still more specific changes. Put global typography and padding in styles, header color in headStyles, numeric alignment in columnStyles, and row striping in alternateRowStyles. This keeps the configuration understandable instead of scattering overrides through data objects.
Fix columns whose styles appear to be ignored
Use the correct column key
If your columns array declares dataKey: 'notes', target that key:
columnStyles: {
notes: { cellWidth: 90, overflow: 'linebreak' }
}
Numeric indexes are for index-based columns. A style aimed at 2 will not affect a data-key column named notes.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteMake widths and overflow explicit
Long URLs, identifiers, or prose can either clip or produce unexpectedly tall rows. Use overflow: 'linebreak' for readable wrapping, or overflow: 'ellipsize' when truncation is preferable. Combine that with a measured cellWidth or 'wrap'. Reduce fontSize and cellPadding when a table is too dense, and consider minCellWidth when narrow columns collapse.
styles: {
fontSize: 8,
cellPadding: 3,
overflow: 'linebreak'
},
columnStyles: {
description: { cellWidth: 85, minCellWidth: 35 },
amount: { cellWidth: 24, halign: 'right' }
}
Align by meaning
Use left alignment for text, right alignment for quantities and currency, and valign: 'top' when wrapped cells should start on the same visual line. Consistent alignment makes dense tables easier to scan than adding more decorative color.
Control page breaks and wide tables
Pagination is independent of styling. The key options are:
Rank #2
- Edit PDFs with Ease. Modify text, images, and layouts directly within your PDF documents.
- Convert & Organize. Export PDFs to Word, Excel, or ePub, and organize files with ease.
- Read & Annotate. Enjoy intuitive reading modes and powerful tools to comment, highlight, and mark up PDFs.
- Create & Manage PDFs. Create new PDFs, combine multiple files, scan documents, and compress for easy sharing.
- Fill & Sign Forms. Complete forms and digitally sign documents with secure e-signature tools.
pageBreak: 'auto'lets the table add pages as required; use the other supported modes when you need a forced start or continuation.rowPageBreak: 'avoid'attempts to keep a row together instead of splitting it.showHead: 'everyPage'repeats the header on each page. Configure footers with the corresponding foot settings when your report needs them.tableWidthcontrols the overall table width when automatic sizing is not suitable.horizontalPageBreakhandles tables wider than the page. Pair it withhorizontalPageBreakRepeatto repeat an identifying column, such as an item name, while the remaining columns continue on subsequent horizontal pages.
A wide table is not fixed by shrinking every font. First decide which columns must remain visible, assign widths, then enable horizontal breaking so the result stays legible.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use hooks at the right time
didParseCell: change parsed content or styles
Use this hook to inspect values and modify the cell before drawing. For example, you can make negative amounts red or replace a value with a display label. It is the right place for content-dependent style decisions.
didParseCell: data => {
if (data.section === 'body' && data.column.dataKey === 'amount' && Number(data.cell.raw) < 0) {
data.cell.styles.textColor = [180, 35, 45]
}
}
willDrawCell: set native jsPDF state before drawing
Native jsPDF color, line, or drawing settings must be applied immediately before the cell is rendered. If a native setting appears to have no effect when placed elsewhere, move it into willDrawCell.
willDrawCell: data => {
if (data.section === 'body' && data.column.index === 0) {
data.doc.setDrawColor(160, 160, 160)
}
}
didDrawCell: add content after rendering
Use didDrawCell for additions that belong after the cell has been drawn, such as an icon, a custom mark, or a post-render annotation. It is not the hook for changing the cell’s existing native drawing state.
Place content after a table
After AutoTable finishes, doc.lastAutoTable.finalY contains the final vertical position. Use it to place a paragraph, signature, or second table without guessing where the first one ended:
const nextY = doc.lastAutoTable.finalY + 10
doc.setFontSize(10)
doc.text('Prepared for internal review', 18, nextY)
This is especially important when wrapping or page breaks make the table height unpredictable.
Choosing between an HTML table and data arrays
HTML input
HTML input is convenient when your page already contains a table and you want to export it. Check the resulting widths and wrapping: browser CSS does not automatically translate into a well-designed PDF layout.
Rank #3
- EVERY PDF TOOL UNLOCKED - 30+ tools in one app: edit text and images, convert, merge, split, compress, sign, OCR, redact, watermark, batch process, and more. No feature gates, no upsells, nothing held back.
- PAY ONCE, OWN FOREVER — A one-time purchase, not a subscription. Other apps runs $240/year — Scrivar is yours for life, with free updates included.
- UNLIMITED eSIGN, BUILT IN — Send contracts and forms for signature and track every step. Recipients sign in their browser with no account or app needed. Replace DocuSign and save hundreds a year.
- PC, MAC, AND WEB — Install on any Win 10/11 PC or macOS 11+ Mac (Intel or Apple Silicon), or work in your browser at scrivar.com. Same tools, same account, everywhere you work.
- OCR + FULL OFFICE CONVERSION — Turn scanned documents into searchable, selectable text, and convert PDFs to and from Word, Excel, and PowerPoint with formatting kept intact.
JavaScript columns and body
Data arrays are preferable for generated reports. Semantic keys such as item, qty, and notes make column styles readable and resilient when you reorder columns.
Troubleshooting checklist
- Header color is missing: verify the color is an RGB number or array, and check that a later section or column rule is not overriding it.
- Column style does nothing: match the key in
dataKey; use a numeric index only with index-based definitions. - Text is cut off: set
overflow: 'linebreak', give the column a usable width, and reduce padding or font size. - Rows become enormous: inspect long unbroken strings, use
ellipsizewhere acceptable, and avoid excessive padding. - Native colors or borders do not appear: move the jsPDF calls into
willDrawCell. - Following text overlaps: calculate its y-coordinate from
doc.lastAutoTable.finalY. - Headers disappear on later pages: set
showHead: 'everyPage'. - A wide table is unreadable: define widths and enable
horizontalPageBreak; repeat an identifying column withhorizontalPageBreakRepeat.
Performance, reliability, and maintenance
Keep the data model separate from presentation settings so you can change a report’s appearance without rewriting its rows. Measure column widths against the actual page margins, test the longest realistic values, and render multi-page samples rather than only a short fixture. Use semantic keys instead of numeric indexes when the table may evolve. Treat pagination and wrapping as test cases: a single unusually long note can change every subsequent y-position.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsOr skip the browser setup
If your goal is a clean screenshot or PDF of a web page rather than a client-side jsPDF report, ScreenshotNeo provides a single API call. It accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and whether it was billed. Its MCP server includes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo documentation for all options. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000, and every feature is available on every plan. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can AutoTable repeat a header on every PDF page?
Yes. Set showHead: 'everyPage' in the table options.
What is the safest way to style generated columns?
Define dataKey values and target those semantic keys in columnStyles; numeric indexes are intended for index-based columns.
Recommended Free Tools
How can I position a second table below the first?
Read doc.lastAutoTable.finalY after the first render and use that value plus your preferred gap as the next y-coordinate.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




