Skip to content

PPTX components

This page is the full props reference for the four non-chart content components you can place on a slide: text, image, shape, and table — plus the two structural ones, group and block. For the two chart components (chart and highcharts) see PPTX charts; for slide structure, groups and the grid system see Slides & grid.

Every component is a JSON object of the form { "name": "...", "props": { ... } }, optionally with id and enabled (set "enabled": false to skip a component at render time without deleting it).

Shared conventions

Position units

All position and size props (x, y, w, h) accept either a number in inches or a percentage string like "50%" (relative to the slide dimensions). Alternatively, place components with the grid prop — a { column, row, columnSpan?, rowSpan? } object resolved against the slide's grid. Explicit x/y/w/h values override the grid-resolved value individually. See Slides & grid for the full grid model.

Alignment enums

  • Horizontal align: left | center | right
  • Vertical valign: top | middle | bottom

Shadow

text, image, and shape accept a shadow object. All fields are optional; the renderer fills in defaults:

FieldTypeRenderer defaultDescription
type'outer' | 'inner''outer'Shadow direction
colorstring (hex)'000000'Shadow color
blurnumber (pt)3Blur radius
offsetnumber (pt)3Distance from the element
anglenumber (deg)45Direction of the offset
opacitynumber (0–1)0.5Shadow opacity
json
{ "shadow": { "type": "outer", "blur": 6, "offset": 2, "opacity": 0.3 } }

text and image accept a hyperlink object: { "url"?: string, "slide"?: number, "tooltip"?: string } — either an external URL or a slide number within the deck.

Colors

Any color prop accepts a hex value ("FF0000" or "#FF0000") or a semantic theme name (primary, secondary, accent, background, text, text2, background2, accent4, accent5, accent6). 3-char shorthand ("F00") is expanded at render time, but props typed with the strict color schema — notably shadow.color — reject it at validation, so use 6-char hex there. Semantic names resolve against the active theme, so the same document re-renders correctly under any theme — see Themes & styling and the theme schema.


text

A text box. The most feature-rich component: it participates in the theme's style-preset cascade (component props override the named style, which overrides theme defaults).

PropTypeDefaultDescription
textstringrequiredText content. Supports {PAGE_NUMBER} and {PAGE_COUNT} placeholders, formatted per the presentation's pageNumberFormat (see Presentation)
fit{ maxLines?, shrink? }Bounded fit. The engine estimates the lines the text takes at its effective size; past maxLines (or the box height when h is set and maxLines is not) it steps down through the shrink sizes in order and takes the first that fits. Nothing else is tried: when no declared size fits, generation fails with text_fit_overflow at the text — or at the block slot the text came from
x, y, w, hnumber (in) | "NN%"Position and size. See auto-height below
gridGridPositionGrid placement ({ column, row, columnSpan?, rowSpan? })
stylestringNamed style preset: title, subtitle, heading1heading3, body, caption
fontSizenumber ≥ 1 (pt)style → theme defaultFont size
fontFacestringstyle → theme fontFalls back to the theme heading font for title/heading* styles, body font otherwise. See Fonts
colorstringstyle → theme defaultHex or semantic color
boldbooleanBold text
fontWeightinteger 100–900Numeric weight; overrides bold. See note below
italicbooleanItalic text
underlineboolean | objecttrue renders a single underline; the object form is { "style"?: "sng" | "dbl" | "dash" | "dotted", "color"?: string }
strikebooleanStrikethrough
languagestring (BCP-47)presentation languageSpell-check language override, e.g. "it-IT"
alignleft | center | rightstyleHorizontal alignment
valigntop | middle | bottom'top'Vertical alignment
breakLinebooleanForce a line break after this text run
bulletboolean | objecttrue for a plain bullet; object form { "type"?: "bullet" | "number", "style"?: string, "startAt"?: number }
marginnumber | [t, r, b, l] (pt)0Inner text-box margin; zero by default so text aligns exactly to the grid
rotatenumber (deg)Rotation
shadowShadowText shadow (see Shadow)
fill{ color, transparency? }Text-box background fill; transparency is 0–100
hyperlink{ url?, slide?, tooltip? }Link on the whole text box
lineSpacingnumber (pt)styleLine spacing
charSpacingnumber (pt)styleCharacter (letter) spacing
paraSpaceBeforenumber (pt)Space before the paragraph
paraSpaceAfternumber (pt)styleSpace after the paragraph

Auto-height: when h is omitted the renderer computes it as max(0.5, fontSize / 72 × 1.6 × lineCount) and marks the element as a text box, so short labels don't reserve a full grid cell of height.

fontWeight aliasing: numeric weights map onto real font variants. The renderer picks the closest registered weight of the family and rewrites fontFace to a synthetic family alias (e.g. Inter at weight 300 becomes "Inter Light"), because PowerPoint itself only understands regular/bold. This works for any registered multi-weight family — see Fonts.

json
{
  "name": "text",
  "props": {
    "text": "Quarterly results",
    "style": "title",
    "color": "primary",
    "shadow": { "blur": 4, "opacity": 0.25 },
    "grid": { "column": 0, "row": 0, "columnSpan": 12, "rowSpan": 2 }
  }
}

image

Embeds a raster image or inline SVG.

PropTypeDefaultDescription
pathstring— *File path or URL
base64string— *Base64 data-URI content
svgstring— *Raw inline SVG markup, embedded as a vector (see below)
x, y, w, hnumber | "NN%"Position and size
sizing{ type, w?, h? }type: contain | cover | crop (see below)
rotatenumber (deg)Rotation
roundingbooleanRounds the image into a circle
shadowShadowDrop shadow (see Shadow)
hyperlink{ url?, slide?, tooltip? }Click-through link
altstringAccessibility alt text
gridGridPositionGrid placement

* Exactly one source is required. Providing more than one non-empty source (path + base64, etc.) fails both validation and generation with a mutually_exclusive error; providing none produces an IMAGE_NO_SOURCE warning and the image is skipped.

Aspect-ratio auto-sizing: if you give exactly one of w/h (and no sizing), the library probes the image's intrinsic dimensions and computes the other side to preserve the aspect ratio.

svg raster fallback: PowerPoint 2016+ draws the vector itself. For everything else — LibreOffice ≤ 7.x, Google Slides, Office < 2016 — the library rasterizes the SVG at ~288 DPI for the box it is placed in and ships that PNG alongside it, so the picture still renders. If the SVG cannot be rasterized you get an IMAGE_SVG_RASTER_FAILED warning and those viewers fall back to a broken-image placeholder; PowerPoint is unaffected either way.

sizing modes:

  • contain — fit the whole image inside the box, centered, preserving aspect ratio (implemented in-house with a probe-and-fit pass for correct results).
  • cover — fill the box, cropping overflow, preserving aspect ratio.
  • crop — crop to the given w/h region.

Remote and local sources are sandboxed

Image probing blocks private/loopback URLs and local paths outside the current working directory. Use base64 or svg for fully self-contained documents.

json
{
  "name": "image",
  "props": {
    "path": "assets/team-photo.jpg",
    "sizing": { "type": "cover" },
    "alt": "The team at the 2026 offsite",
    "grid": { "column": 6, "row": 1, "columnSpan": 6, "rowSpan": 4 }
  }
}

shape

A geometric shape, optionally with text inside it. With text set, the renderer emits a text box shaped like the geometry; without it, a plain shape.

Shape types (type is required). Left column is what you write; right column is the underlying pptxgenjs shape it maps to:

typepptxgenjs shape
rectrect
roundRectroundRect
ellipseellipse
triangletriangle
diamonddiamond
pentagonpentagon
hexagonhexagon
star5star5
star6star6
lineline
arrowrightArrow
chevronchevron
cloudcloud
heartheart
lightninglightningBolt
PropTypeDefaultDescription
typeShapeTyperequiredOne of the 15 types above
x, y, w, hnumber | "NN%"Position and size
fill{ color, transparency? }Fill color; transparency is 0–100
line{ color?, width?, dashType? }Outline; width in pt; dashType: solid | dash | dot | dashDot
textstring | TextSegment[]Text inside the shape; array form gives rich multi-run text (below)
fontSize, fontFace, fontColor, charSpacing, bold, fontWeight, italicas in textstyle/theme cascadeTypography for the shape's text; fontColor accepts semantic names
align / valignalignment— / 'top'Text alignment inside the shape
rotatenumber (deg)Rotation
shadowShadowDrop shadow (see Shadow)
rectRadiusnumber ≥ 0 (in)Corner radius, only meaningful for roundRect
gridGridPositionGrid placement
stylestringNamed style preset

TextSegment — each run in the array form of text:

FieldTypeDescription
textstring (required)Run content
fontSizenumber (pt)Per-run size
fontFacestringPer-run family
colorstringHex or semantic
boldbooleanBold run
fontWeightinteger 100–900Numeric weight; same aliasing as text
italicbooleanItalic run
breakLinebooleanLine break after this run
spaceBefore / spaceAfternumber (pt)Paragraph spacing around the run
charSpacingnumber (pt)Letter spacing
json
{
  "name": "shape",
  "props": {
    "type": "roundRect",
    "rectRadius": 0.08,
    "fill": { "color": "primary", "transparency": 10 },
    "text": [
      {
        "text": "42%",
        "fontSize": 40,
        "bold": true,
        "color": "background",
        "breakLine": true
      },
      { "text": "of respondents agreed", "fontSize": 14, "color": "background" }
    ],
    "align": "center",
    "valign": "middle",
    "grid": { "column": 0, "row": 2, "columnSpan": 4, "rowSpan": 3 }
  }
}

table

A data table. Cells may be plain strings or objects with per-cell formatting and spans.

PropTypeDefaultDescription
rowsCell[][] (min 1 row)requiredArray of rows; each cell is a string or a Cell object (below)
x, y, w, hnumber | "NN%"Position and size
colWnumber | number[] (in)Uniform column width, or one width per column
rowHnumber | number[] (in)Uniform row height, or one height per row
border{ type?, pt?, color? }Cell borders; type: solid | dash | dot | none; pt defaults to 1, color to '000000'
fillstringTable background (hex or semantic)
fontSizenumber ≥ 1 (pt)theme defaultDefault cell font size
fontFacestringtheme body fontDefault cell font
fontWeightinteger 100–900Default cell weight; same aliasing as text. A cell setting its own fontWeight/bold opts out
colorstringDefault cell text color
align / valignalignment— / 'middle'Default cell alignment
autoPagebooleanAutomatically continue the table on new slides when it overflows
autoPageRepeatHeaderbooleanWith autoPage, repeat row 1 as a header on every continuation slide
marginnumber | [t, r, b, l] (pt)Cell inner margin
borderRadiusnumber ≥ 0 (in)Rounded table corners (see below)
gridGridPositionGrid placement

Cell object:

FieldTypeDescription
textstring (required)Cell content
color, fillstringPer-cell text/background color
fontSize, fontFace, bold, italicas in textPer-cell typography
fontWeightinteger 100–900Overrides bold, same aliasing as text
align / valignalignmentPer-cell alignment
colspan / rowspaninteger ≥ 1Merge cells across columns/rows
marginnumber | [t, r, b, l]Per-cell margin

Rounded corners (borderRadius): PowerPoint tables can't natively have rounded corners, so the renderer composes them — it draws a roundRect and a rect behind the table, makes the corner cells transparent, and re-applies borders per-cell. This trick requires numeric x and y (not percentages; using grid is fine since it resolves to inches) and at least 2 rows.

Table style neutralized

pptxgenjs applies PowerPoint's "Medium Style 2 – Accent 1" table style by default, which forces all-caps headers and banded fills. json-to-office post-processes the file to swap in "No Style, No Grid", so your cells render exactly as authored.

Symbols render as text, not emoji

Glyphs that PowerPoint tends to render as color emoji (✓, ✗, ★, …) automatically get a text-presentation selector appended, so they follow your cell's font color.

json
{
  "name": "table",
  "props": {
    "rows": [
      [
        {
          "text": "Region",
          "bold": true,
          "fill": "primary",
          "color": "background"
        },
        {
          "text": "Q1",
          "bold": true,
          "fill": "primary",
          "color": "background"
        },
        { "text": "Q2", "bold": true, "fill": "primary", "color": "background" }
      ],
      ["EMEA", "1.2M", "1.4M"],
      ["APAC", "0.8M", "1.1M"],
      [{ "text": "Total", "bold": true, "colspan": 1 }, "2.0M", "2.5M"]
    ],
    "colW": [2.5, 1.5, 1.5],
    "border": { "type": "solid", "pt": 1, "color": "DDDDDD" },
    "autoPage": true,
    "autoPageRepeatHeader": true,
    "grid": { "column": 0, "row": 1, "columnSpan": 8, "rowSpan": 4 }
  }
}

group

A transparent container, and the inspectable result of block expansion. Without a frame it is a plain sequence: its children position exactly as they would on the slide. With a frame it is a nested coordinate system; with a direction it distributes its children into cells — the engine operation a two-to-four metric row or a two-column split needs, so that adapting to a count never requires a plugin.

PropTypeDefaultDescription
x, ynumber (in) | "NN%"Frame origin, relative to the enclosing frame or slide. Percentages are fractions of the enclosing width and height.
w, hnumber (in) | "NN%"Frame size. Omitted, the frame fills the enclosing extent.
gridGridPositionFrame placement on the enclosing grid, as for any component.
gridConfigGridConfigGrid for grid placements of this group’s descendants, merged over the enclosing grid field by field. Inside a frame the grid spans the frame; the enclosing margin is dropped unless stated here.
direction"row" | "column"Distribute the enabled children into cells along this axis, equal or weighted. A child fills its cell unless it states its own offsets; an omitted optional child simply redistributes the rest.
gapnumber (in)0Space between distributed cells.
weightsnumber[]Relative cell sizes in child order, e.g. [1.1, 1] for a 1.1 : 1 split. Missing entries count as 1.

Inside a frame, a child's numeric x/y are offsets from the frame origin, percentages are fractions of the frame, and an omitted x/y or w/h means the frame's. A group holds what a slide holds — content components, blocks and further groups — and never a slide or the pptx root.


block

Invoke a JSON block defined in the presentation's props.blocks. The two props are the whole contract: ref names a definition in this document, and slots supplies its content. No coordinates are accepted here, and a component placed in a slot may not carry x, y, w, h or grid: geometry lives in the definition. See JSON blocks.

PropTypeDefaultDescription
refstringrequired. Name of a definition in props.blocks. An unknown name fails validation.
slotsRecord<string, unknown>Values keyed by the slot names the definition declares; unknown slots and budgets are errors.

See also

  • PPTX charts — the chart and highcharts components
  • Slides & grid — slide props, groups and frames, grid resolution
  • JSON blocks — document-local definitions, slots, slide effects, fit
  • Theme schema — semantic colors, style presets, component defaults
  • Fonts — font registration and fontWeight variants

Released under the MIT License.