Two practical patterns — from the simplest “a designer hands me
a finished .pptx, code just swaps the numbers” to a
fully code-built deck. Each has a flow diagram so you can see
where the data and the file move. The buttons at the top of the
page are working demos of both.
| I want to… | Use | Effort |
|---|---|---|
| Have a designer own the layout; pull numbers from a database, JSON, or form. | Method 1 — {{token}} swap on a template .pptx. |
1–2 hrs |
| Let users click a button on my web page / app and download a fresh deck built from data. | Method 2 — build the slide in JavaScript (PptxGenJS). | 2–3 hrs |
The template uses double-brace tokens like {{REVENUE}}
and {{PIPELINE}}. The pattern is the same whether you
do it in the browser (JSZip), Node.js (docxtemplater + pptx
module), or Python (python-pptx): load the file, walk every text
run, and replace the tokens with values from your data source.
The Download from template button above is a
working browser-only implementation — on load it looks for
template/SalesReview-Template.pptx in this folder
and uses it automatically; if it isn’t there, an in-memory built-in
template is used instead. Here’s the same idea in Python:
Designer owns the layout; code owns the numbers. Moving shapes in the template doesn’t require a code change.
# Python example using python-pptx — fills {{TOKEN}} placeholders in an existing .pptx # pip install python-pptx from pptx import Presentation # 1. The data you want to inject. Keys MUST match the {{TOKEN}} names in the template. # In production this dict would come from your DB / API / form submission. data = { "REVENUE": "$12.4M", "REVENUE_DELTA": "+8.2% YoY", "PLAN_ATTAINMENT": "104%", "PIPELINE": "$18.1M", "WIN_RATE": "36%", } # 2. Open the designer-built template (the .pptx that contains the {{TOKEN}} strings). prs = Presentation("SalesReview-Template.pptx") # 3. Walk every slide → every shape → every paragraph → every text run, and # replace any {{TOKEN}} we recognize. Working at the "run" level preserves # the original font, size, color, and bold/italic formatting from the template. for slide in prs.slides: for shape in slide.shapes: if not shape.has_text_frame: continue # skip pictures, charts, lines, etc. for para in shape.text_frame.paragraphs: for run in para.runs: for k, v in data.items(): run.text = run.text.replace(f"{{{{{k}}}}}", v) # 4. Save under a new name so the original template is never overwritten. prs.save("SalesReview-Q2-2026.pptx")
For dashboards where users click a button and download a ready-made deck, you don’t need a template file at all — PptxGenJS builds a fully native PowerPoint file in JavaScript. The Generate a .pptx from this page button above runs exactly this code:
Pure-client generation. Great when there’s no backend — or you don’t want one in the loop.
// JavaScript example using PptxGenJS — builds a .pptx in the browser from data. // Loaded via <script src="...pptxgen.bundle.js"> — no build step / no server needed. // 1. Create the deck and pick a slide size. LAYOUT_WIDE = 13.33" x 7.5" (16:9). // Other options: "LAYOUT_4x3" (10"x7.5"), "LAYOUT_16x9" (10"x5.625"), or custom inches. const pptx = new PptxGenJS(); pptx.layout = "LAYOUT_WIDE"; // 2. (Optional) Define a brand theme in one place so every shape reuses it. // Colors are 6-digit hex strings WITHOUT the leading "#". Sizes are in points. const theme = { accent: "005EB8", // brand blue — swap to your own (e.g. "D71920" for red) deep: "003B71", // deep navy for table headers text: "1B1F24", // near-black body text muted: "5C6670", // secondary / label gray green: "2E7D32", // positive delta fontTitle: "Aptos Display", // big headings (any installed font name works) fontBody: "Aptos" // body text — try "Calibri", "Segoe UI", "Arial", etc. }; // 3. Add a slide. You can set a solid background or a hex color. const slide = pptx.addSlide(); slide.background = { color: "FFFFFF" }; // e.g. "F5F8FC" for soft blue page // 4. addText() options control color, size, font, alignment, etc. // Most-used keys: x, y, w, h (inches), fontSize (pt), fontFace, color (hex), // bold, italic, underline, align ("left"|"center"|"right"), valign, charSpacing. slide.addText("BUSINESS REVIEW", { x:0.5, y:0.4, w:5, h:0.3, fontSize:10, bold:true, color: theme.accent, fontFace: theme.fontBody, charSpacing:2 // 0.1pt letter spacing — try 0 to disable }); slide.addText(sampleData.title, { x:0.5, y:0.7, w:9, h:0.6, fontSize:28, bold:true, // bump to 36 for a bigger headline color: theme.text, fontFace: theme.fontTitle }); // 5. KPI tiles — a single addText() call can hold multiple text runs, // each with its own font / color / size. Great for label-over-value tiles. sampleData.kpis.forEach((k, i) => { const col = i % 2, row = Math.floor(i/2); slide.addText( [ { text:k.label+"\n", options:{ fontSize:9, bold:true, color: theme.muted } }, { text:k.value+"\n", options:{ fontSize:22, bold:true, color: theme.text } }, // raise to 28 for emphasis { text:k.delta, options:{ fontSize:10, bold:true, color: theme.green } } // red "B23A48" if negative ], { x: 0.5 + col*1.85, y: 2.6 + row*1.15, w:1.75, h:1, fill: { color:"FFFFFF" }, // tile background line: { color:"C8D3E0", width:0.5 }, // border color + thickness (pt) fontFace: theme.fontBody, valign:"middle" } ); }); // 6. addShape() draws a native PowerPoint shape — perfect for accents / dividers. slide.addShape(pptx.ShapeType.rect, { x:0.5, y:1.6, w:0.4, h:0.05, fill:{ color: theme.accent }, line:{ color: theme.accent } }); // 7. Native PowerPoint chart from the same sample data. // chartColors[] sets the series colors in order. showLegend / legendPos control the legend. slide.addChart(pptx.ChartType.bar, [ { name:"Plan", labels:sampleData.chart.labels, values:sampleData.chart.plan }, { name:"Actual", labels:sampleData.chart.labels, values:sampleData.chart.actual } ], { x:5, y:2.2, w:7.5, h:3, chartColors:["C8D3E0", theme.accent], // one color per data series showLegend:true, legendPos:"b", // "b"=bottom, "t"=top, "l"=left, "r"=right legendFontSize:9, legendFontFace: theme.fontBody, catAxisLabelFontSize:9, valAxisLabelFontSize:9, catAxisLabelColor: theme.muted, valAxisLabelColor: theme.muted }); // 8. Trigger the browser download. Use pptx.write({outputType:"blob"}) instead // if you want to email / upload the file rather than download it. pptx.writeFile({ fileName:"SalesReview.pptx" });
sampleData object drives the on-page KPIs, the live Chart.js chart, the data table, and the generated .pptx — one source of truth.sampleData for a fetch() against your real API and the rest of the page (and the generated deck) will just work.Two copy-paste prompts — one per method on this page. Replace every [bracketed] placeholder with details from your own deck / data and paste the result into ChatGPT, Claude, or any code-capable LLM.
I want a working script that fills {{TOKEN}} placeholders in a PowerPoint
template with data from my application.
Language / runtime: [Python with python-pptx | Node.js | Browser JS with JSZip]
Template file path: [path/to/Template.pptx]
Output file path: [path/to/Output-{{DATE}}.pptx]
Data source (describe the shape, or paste a small sample):
[ e.g. JSON object, SQL query result, REST API response, CSV row ]
Tokens I need to replace (token name -> what it should be filled with):
{{TITLE}} -> [report title, e.g. data.title]
{{SUBTITLE}} -> [period / scope, e.g. "Q2 2026 · NA Region"]
{{REVENUE}} -> [formatted currency, e.g. f"${data.revenue:,.1f}M"]
{{REVENUE_DELTA}} -> [signed % vs prior period]
{{ROW1_METRIC}} -> [table row 1 label]
{{ROW1_CURRENT}} -> [table row 1 current value]
[ ...add as many tokens as your template uses... ]
Requirements:
1. Walk every slide AND every notes slide so no tokens are missed.
2. Replace tokens at the text-run level so the template's fonts, sizes,
colors, and bold/italic styling are preserved.
3. Leave unknown {{TOKENS}} alone (don't crash) so the author can spot
them in the output.
4. Never overwrite the original template — always write to a new file.
5. Add short comments above each step so I can extend it later.
Optional extras:
[ ] also fill {{TOKENS}} inside grouped shapes
[ ] log how many tokens were swapped per slide
[ ] expose CLI flags for input/output paths
Build me a PptxGenJS function that generates a .pptx in the browser
(no server, no template file) from JavaScript data. I want to drop it
into a button click handler.
Output: one self-contained function `generateDeck(data)` that ends with
`pptx.writeFile({ fileName: ... })`.
Slide size: [LAYOUT_WIDE 13.33"x7.5" | LAYOUT_4x3 10"x7.5" | LAYOUT_16x9 10"x5.625"]
Brand theme (6-digit hex, no leading "#"):
accent: [005EB8]
deep: [003B71]
text: [1B1F24]
muted: [5C6670]
positive: [2E7D32]
negative: [B23A48]
Fonts:
title: [Aptos Display]
body: [Aptos]
Data shape I'll pass in:
{
title: "[Report title]",
subtitle: "[Period / scope]",
kpis: [
{ label: "[KPI label]", value: "[value]", delta: "[+/-x%]" }
// ...as many as needed
],
chart: {
labels: ["Q1", "Q2", "Q3", "Q4"],
series: [
{ name: "[Plan]", values: [/* numbers */] },
{ name: "[Actual]", values: [/* numbers */] }
]
},
table: [
{ metric: "[name]", current: "[v]", prior: "[v]", variance: "[v]", notes: "[v]" }
// ...
]
}
Slide layout (left to right, top to bottom):
1. Tiny uppercase kicker top-left ("[BUSINESS REVIEW]")
2. Large bold title bound to data.title
3. Smaller muted subtitle bound to data.subtitle
4. 2x2 KPI tile grid on the left (label / value / colored delta —
positive color for "+" deltas, negative color for "-" deltas)
5. Native PowerPoint bar chart on the right using chart.series,
chartColors=[muted, accent], legend at bottom
6. Optional data table along the bottom with a deep-navy header row
7. Small muted page number bottom-right
Requirements:
1. Put colors / fonts in a single `theme` object so they're easy to swap.
2. Add a short comment above each major step (kicker, title, KPIs, chart,
table, page number) so I can find and edit each block quickly.
3. Pure PptxGenJS — no external CSS, no HTML — works from any page.
4. End with pptx.writeFile to trigger the browser download.
Optional extras:
[ ] addShape() accent bar under the title
[ ] second slide that's notes-only
[ ] return the Blob instead of downloading (for upload / email flows)