Skip to main content

html-to-pptx

Convert HTML slide decks into editable PowerPoint files.

Unlike screenshot-based approaches that produce flat images, html-to-pptx measures every DOM element in a headless browser and maps it to a native PPTX shape — text boxes you can edit, images you can resize, backgrounds you can restyle. The output is a real presentation, not a picture of one.

Install

pip install html-to-pptx
python -m playwright install chromium

Quick start

CLI

html-to-pptx deck.html deck.pptx

Python

import asyncio
from html_to_pptx import convert

asyncio.run(convert("deck.html", "deck.pptx"))

Two-stage API

For more control, separate the measurement and rendering steps:

import asyncio
from html_to_pptx import extract_measurements, render_pptx

async def main():
    # Stage 1: measure DOM elements in a headless browser
    measurements = await extract_measurements("deck.html")

    # Stage 2: render measurements to python-pptx shapes
    prs = render_pptx(measurements)

    # Modify the presentation before saving
    prs.slides[0].shapes[0].text = "Custom title"
    prs.save("deck.pptx")

asyncio.run(main())

Measuring a page you already control

If you already drive Playwright (custom viewport, auth, injected data), measure the loaded page directly. Fonts are awaited, animations settled, and non-native paint rasterized in the same page:

from html_to_pptx import extract_from_page, render_pptx

measurements = await extract_from_page(page)
render_pptx(measurements).save("deck.pptx")

HTML format

Slides are discovered the way common deck frameworks expose them: .slide elements first, then reveal.js-style .slides > section, then any section, then the children of a #deck/.deck/.slides container. Each slide is revealed by removing inline display:none and adding the active/present/current classes, so your own .slide.active { display: grid } rules keep working. A 1920×1080 canvas is expected:

<!DOCTYPE html>
<html>
<head>
<style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { background: #000; overflow: hidden; }
    .slide {
        width: 1920px;
        height: 1080px;
        display: none;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        font-family: sans-serif;
    }
    .slide.active { display: flex; }
</style>
</head>
<body>

<section class="slide active" style="background-color: #1e293b;">
    <h1 style="font-size: 64px; color: #f8fafc;">Hello World</h1>
</section>

<section class="slide" style="background-color: #ffffff;">
    <p style="font-size: 24px; color: #334155;">Second slide</p>
</section>

</body>
</html>

See examples/demo.html for a full five-slide deck.

What gets converted

HTML feature PPTX output
Text with fonts, colors, weight, style Editable text boxes with matching font properties
Font substitution (web fonts like Inter, Playfair, Roboto) Mapped to a metric-compatible, install-safe font in the same family so headings don't reflow
Single-line fit One-line headings/pills/buttons never wrap — the point size auto-shrinks to fit the box
CSS line-height Exact paragraph line spacing (multi-line headings keep their height)
CSS padding Reproduced as text-frame insets (bulleted/labelled text aligns correctly)
Text/box/gradient alpha Flattened over the correct backdrop (nearest ancestor bg), so translucency renders in every viewer
Translucent image overlays / scrims Baked into the underlying image so the photo stays visible
Mixed inline content (<p>text <strong>bold</strong> more</p>) Multi-run paragraphs with per-run styling
CSS linear-gradient backgrounds OOXML gradient fills with angle (deg/turn/rad/grad), exact stop positions, hard stops and double-position stops
Paint PPTX can't express (radial/conic/repeating/layered gradients, background-image: url(), glows, filter, clip-path, mask, decorative ::before/::after) Only the element's own paint is screenshotted by Chromium and placed underneath — its text and children stay native and editable
box-shadow Native OOXML outer shadow (blur, offset, spread, alpha); layered shadows use the dominant layer
Gradient text (-webkit-background-clip: text) Gradient text fill with a solid first-stop fallback
Inline <svg>, <canvas>, <video>, <iframe> Pixel-exact picture captured in isolation at 2× device scale
Any <img> (WebP, AVIF, SVG, remote, relative URLs) Native picture; non-PPTX formats are captured or transcoded to PNG
letter-spacing, text-decoration Run character spacing, underline, strikethrough
Per-side borders (border-bottom dividers, table row rules) Thin bars at the exact side and width
CSS animations/transitions Settled to their final state before measuring, so fade-ins aren't captured mid-flight
Speaker notes (<aside class="notes"> or data-pptx-notes) PowerPoint speaker notes
HTML tables (<table>) Cell-accurate text with per-column alignment preserved
Background colors Solid fills (with alpha flattening)
Rounded corners (border-radius, including %) OOXML adjustment guides on rounded rectangles
Rounded images (border-radius on <img> or wrapper) Rounded-rect geometry swap on picture shapes
object-fit: cover Centered crop (no distortion) instead of stretching
Base64-embedded images (data:image/...) Native picture shapes
Borders (with alpha) Shape outlines with color, width, and opacity
Left/top accent bars (border-left, ::before strips) Rounded to match the card's corners (offset under-component)
transform: rotate() Shape rotation about the element center
writing-mode: vertical-* Vertical PPTX text body
Flex/grid alignment (justify-content, align-items) Horizontal + vertical text anchoring
text-transform (uppercase, etc.) Transformed text content
Hyperlinks Preserved on text runs
Ordered/unordered lists (incl. custom bullet dots) Bullet/number prefixes and decorative markers
CSS ::before/::after pseudo-elements Synthetic shapes for decorative accents
white-space: pre (terminals/code) Preserved line breaks and indentation
RTL text direction Correct paragraph alignment
<br> tags in inline runs Multi-paragraph text frames
Element opacity (incl. inherited) OOXML alpha / picture transparency

How it works

HTML file
    │
    ▼
┌─────────────────────────┐
│  Headless Chromium       │  ← Playwright loads the HTML at 1920×1080
│  (Playwright)            │
│                          │
│  For each slide:         │
│  • Reveal it, settle     │
│    animations            │
│  • Clear CSS transforms  │
│  • Measure every visible │
│    element recursively:  │
│    position, size, color,│
│    font, text, images    │
│  • Screenshot paint PPTX │
│    can't express, in     │
│    isolation             │
└───────────┬─────────────┘
            │
            ▼
    Measurement tree (JSON)
            │
            ▼
┌─────────────────────────┐
│  python-pptx renderer    │
│                          │
│  For each element:       │
│  • Text leaf → text box  │
│  • Image → picture shape │
│  • Background → rectangle│
│  • Border → outline/shape│
│                          │
│  Coordinates:            │
│  CSS px → inches using   │
│  13.333/1920 ratio       │
└───────────┬─────────────┘
            │
            ▼
      Editable .pptx

Visual comparison tool

Verify conversion quality with side-by-side comparisons:

pip install html-to-pptx[compare]
html-to-pptx-compare deck.html -o results/

This screenshots the original HTML, converts to PPTX, renders the PPTX back to images via LibreOffice, and creates side-by-side comparison PNGs. Requires LibreOffice on PATH.

Output structure:

results/deck/
├── html_slide_0.png      # ground truth (HTML screenshot)
├── html_slide_1.png
├── pptx_slide_0.png      # converter output (PPTX rendered via LibreOffice)
├── pptx_slide_1.png
├── compare_slide_0.png   # side-by-side comparison
├── compare_slide_1.png
└── output.pptx           # the generated file

Limitations

  • Rasterized paint is a picture — radial gradients, glows, url() backgrounds and SVG/canvas content look exact but can't be restyled in PowerPoint (text on top of them stays editable)
  • Inset and multi-layer shadows — OOXML allows one outer shadow per shape; inset layers are dropped
  • Animations and transitions are not represented in PPTX — each slide shows its final, settled state
  • Font availability — web fonts are mapped to a metric-compatible font in the same family (serif→Georgia, humanist sans→Segoe UI, geometric sans→Century Gothic, mono→Consolas, …). For pixel-exact display type, embed the font in PowerPoint yourself
  • Complex CSS layouts (grid, advanced flexbox) are measured as-rendered, but deeply nested layouts may lose some positioning precision

Development

git clone https://github.com/Design-Arena/html-to-pptx.git
cd html-to-pptx
pip install -e ".[dev]"
python -m playwright install chromium
pytest -v

License

MIT

Metadata

Release files for html-to-pptx 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for html-to-pptx 0.4.0
File Size Uploaded Provenance
html_to_pptx-0.4.0.tar.gz 57.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for html-to-pptx 0.4.0
File Interpreter ABI Platform
html_to_pptx-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.5 kB

Release files / html_to_pptx-0.4.0.tar.gz

Download URL html_to_pptx-0.4.0.tar.gz
Size 57.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b444aa0297c1fcad0667d7c373d8d8ac9ea09cd37a784d9a0484290663593db4
BLAKE2b-256 checksum
How to use checksums
4366aa08ecb65154808b587b8b1e4a76ab208489700f8b8733fc7d446ce078cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / html_to_pptx-0.4.0-py3-none-any.whl

Download URL html_to_pptx-0.4.0-py3-none-any.whl
Size 50.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
edf59f93bc056ac4021cc766b3ef08d6d98b685f3220ed341701232631882c9d
BLAKE2b-256 checksum
How to use checksums
e3b4d0fd704c365f6f2395a44a1a4edc2a2bf925f4f9fff700d9fcd048035013
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for html-to-pptx 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for html_to_pptx-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page