pptx/slide-title

A slide carries a title placeholder shape whose text body contains the slide title.

Library verdicts: python-pptx: — pptxjs: fail

Metadata

Feature idpptx/slide-title
Formatpptx
Categoryslide-layout
Spececma-376-5-part-1 § 19.3.1 p:ph

XPath assertions

ID / partPredicateXPathpython-pptxpptxjs
title-placeholder-text-present
ppt/slides/slide1.xml
exist
A shape marked as a title or centre-title placeholder must carry a text run whose value is 'Hello slide world'.
//p:sp[p:nvSpPr/p:nvPr/p:ph[@type='ctrTitle' or @type='title']]//a:t[normalize-space()='Hello slide world']
title-placeholder-type
ppt/slides/slide1.xml
match = ^(ctrTitle|title)$
The placeholder carrying the title text must declare type='ctrTitle' or type='title'.
//p:sp[.//a:t[normalize-space()='Hello slide world']]/p:nvSpPr/p:nvPr/p:ph/@type

Render assertions

IDPredicateSelectorpython-pptxpptxjs
slide-title-text-presentcss_selector/ match-text = Hello slide world
A DOM node marked as a title placeholder (via data-placeholder-type or a .pptx-title class) must contain the slide title text. Falls back to h1/h2 for renderers that use semantic HTML for titles.
[data-placeholder-type='ctrTitle'], [data-placeholder-type='title'], .pptx-title, h1, h2fail
slide-title-visual-ssimvisual_ssim
A Playwright screenshot of the rendered slide must score >= 0.80 SSIM against the LibreOffice-rendered reference PNG (refs/pptx/slide-title-page1.png, resolved by the runner from the machine-fixture name). Threshold is lower than docx (0.85) because pptx slides carry shape, background, and positioning variance that can't be perfectly reproduced by a web renderer.
slide-countcss_selector/ equal-count
Exactly one slide container must be rendered. Catches renderers that emit zero slides (hard failure) or duplicate the slide.
section.pptx-slide, .pptx-slide, section[data-slide], .slide, [data-slide]
slide-title-has-heading-rolecss_selector/ exist
Accessibility: the slide title should carry heading semantics — a semantic <h1>/<h2>, an explicit role='heading', or (if it's used as the slide's aria-labelledby target) an id so the slide landmark can reference it. Accepts any of these; a plain styled <div>/<span> with no heading signal and no id fails this assertion.
h1, h2, [role='heading'], [data-placeholder-type='ctrTitle'][id], [data-placeholder-type='title'][id], .pptx-title[id]
slide-has-landmark-a11ycss_selector/ exist
Accessibility: a slide should surface as a landmark for screen readers — either with a landmark role (region/article/group), or hooked to the title via aria-labelledby, or named with aria-label. Accepts any of these; a renderer that emits the slide as a plain <div> with no ARIA hook fails this assertion.
[role='region'], [role='article'], [role='group'], [aria-labelledby], [aria-label], section[aria-label], section[aria-labelledby], .pptx-slide[aria-label], .pptx-slide[aria-labelledby], [data-slide-index][aria-label], [data-slide-index][aria-labelledby]

Generator source

scripts/gen_slide_title.py

#!/usr/bin/env python3
"""Generate ``fixtures/pptx/slide-title.pptx``.

A minimal one-slide presentation exercising the ``p:ph type="ctrTitle"``
title placeholder. Designed to satisfy the assertions in
``features/pptx/slide-title.json``.
"""

from __future__ import annotations

from pathlib import Path

from pptx import Presentation

import datetime as _dt
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)

_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "pptx" / "slide-title.pptx"


def main() -> int:
    prs = Presentation()
    slide = prs.slides.add_slide(prs.slide_layouts[0])
    slide.shapes.title.text = "Hello slide world"
    _OUT.parent.mkdir(parents=True, exist_ok=True)
    prs.save(_OUT, zip_date_time=_REPRODUCIBLE_DT)
    print(_OUT)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "pptx/slide-title",
  "title": "Slide title placeholder",
  "format": "pptx",
  "category": "slide-layout",
  "summary": "A slide carries a title placeholder shape whose text body contains the slide title.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "19.3.1",
    "element": "p:ph",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/PresentationML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/pml.xsd",
    "notes": "PowerPoint marks a title placeholder with <p:ph type=\"ctrTitle\"/> on a centre-title layout (slide_layouts[0]) or <p:ph type=\"title\"/> on other layouts. The assertion accepts either. Text lives in the <p:txBody>/<a:p>/<a:r>/<a:t> chain on the same <p:sp>. visual_ssim uses min_ssim=0.80 — pptx slides carry more visual complexity (shapes, text positioning, layout backgrounds) than a flat docx page, so the threshold is lower than the docx default of 0.85."
  },
  "fixtures": {
    "machine": "pptx/slide-title",
    "office": "pptx/slide-title"
  },
  "generator": {
    "python": "scripts/gen_slide_title.py"
  },
  "assertions": [
    {
      "id": "title-placeholder-text-present",
      "part": "ppt/slides/slide1.xml",
      "namespaces": {
        "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
        "a": "http://schemas.openxmlformats.org/drawingml/2006/main"
      },
      "xpath": "//p:sp[p:nvSpPr/p:nvPr/p:ph[@type='ctrTitle' or @type='title']]//a:t[normalize-space()='Hello slide world']",
      "must": "exist",
      "description": "A shape marked as a title or centre-title placeholder must carry a text run whose value is 'Hello slide world'."
    },
    {
      "id": "title-placeholder-type",
      "part": "ppt/slides/slide1.xml",
      "namespaces": {
        "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
        "a": "http://schemas.openxmlformats.org/drawingml/2006/main"
      },
      "xpath": "//p:sp[.//a:t[normalize-space()='Hello slide world']]/p:nvSpPr/p:nvPr/p:ph/@type",
      "must": "match",
      "value": "^(ctrTitle|title)$",
      "description": "The placeholder carrying the title text must declare type='ctrTitle' or type='title'."
    }
  ],
  "render_assertions": [
    {
      "id": "slide-title-text-present",
      "kind": "css_selector",
      "selector": "[data-placeholder-type='ctrTitle'], [data-placeholder-type='title'], .pptx-title, h1, h2",
      "must": "match-text",
      "value": "Hello slide world",
      "description": "A DOM node marked as a title placeholder (via data-placeholder-type or a .pptx-title class) must contain the slide title text. Falls back to h1/h2 for renderers that use semantic HTML for titles."
    },
    {
      "id": "slide-title-visual-ssim",
      "kind": "visual_ssim",
      "min_ssim": 0.8,
      "description": "A Playwright screenshot of the rendered slide must score >= 0.80 SSIM against the LibreOffice-rendered reference PNG (refs/pptx/slide-title-page1.png, resolved by the runner from the machine-fixture name). Threshold is lower than docx (0.85) because pptx slides carry shape, background, and positioning variance that can't be perfectly reproduced by a web renderer."
    },
    {
      "id": "slide-count",
      "kind": "css_selector",
      "selector": "section.pptx-slide, .pptx-slide, section[data-slide], .slide, [data-slide]",
      "must": "equal-count",
      "count": 1,
      "description": "Exactly one slide container must be rendered. Catches renderers that emit zero slides (hard failure) or duplicate the slide."
    },
    {
      "id": "slide-title-has-heading-role",
      "kind": "css_selector",
      "selector": "h1, h2, [role='heading'], [data-placeholder-type='ctrTitle'][id], [data-placeholder-type='title'][id], .pptx-title[id]",
      "must": "exist",
      "description": "Accessibility: the slide title should carry heading semantics — a semantic <h1>/<h2>, an explicit role='heading', or (if it's used as the slide's aria-labelledby target) an id so the slide landmark can reference it. Accepts any of these; a plain styled <div>/<span> with no heading signal and no id fails this assertion."
    },
    {
      "id": "slide-has-landmark-a11y",
      "kind": "css_selector",
      "selector": "[role='region'], [role='article'], [role='group'], [aria-labelledby], [aria-label], section[aria-label], section[aria-labelledby], .pptx-slide[aria-label], .pptx-slide[aria-labelledby], [data-slide-index][aria-label], [data-slide-index][aria-labelledby]",
      "must": "exist",
      "description": "Accessibility: a slide should surface as a landmark for screen readers — either with a landmark role (region/article/group), or hooked to the title via aria-labelledby, or named with aria-label. Accepts any of these; a renderer that emits the slide as a plain <div> with no ARIA hook fails this assertion."
    }
  ]
}

Fixture

Download slide-title.pptx (27.5 KB)

Reference preview

Reference (machine, page 1 PNG)

pptx/slide-title page 1 reference

Reference PDF


Download PDF Open in PDF.js

Spec notes

PowerPoint marks a title placeholder with <p:ph type="ctrTitle"/> on a centre-title layout (slide_layouts[0]) or <p:ph type="title"/> on other layouts. The assertion accepts either. Text lives in the <p:txBody>/<a:p>/<a:r>/<a:t> chain on the same <p:sp>. visual_ssim uses min_ssim=0.80 — pptx slides carry more visual complexity (shapes, text positioning, layout backgrounds) than a flat docx page, so the threshold is lower than the docx default of 0.85.