# TSX elements and templates

`@office-kit/pptx-dsl` turns typed TSX into native PPTX objects through
`@office-kit/pptx`. It has its own JSX runtime; it does not use React, Vue, the DOM,
or CSS layout. To install and preview a project, follow
[Create slides with AI](/pptx/docs/authoring) first. To try TSX without
installing anything, open the [REPL's TSX tab](/pptx/repl?mode=tsx).

## A complete deck

Replace the generated `deck.tsx` with the following, then save:

```tsx
import { Presentation, Slide, Text, Chart } from '@office-kit/pptx-dsl';

export default (
  <Presentation>
    <Slide background="#15171C">
      <Text x={1} y={2.5} width={11} height={1} size={44} bold color="#FFFFFF">
        Quarterly business review
      </Text>
    </Slide>
    <Slide background="#FFFFFF">
      <Text x={0.9} y={0.5} width={11.5} height={0.8} size={30} bold>
        Revenue by quarter
      </Text>
      <Chart
        x={0.9} y={1.7} width={11.5} height={5}
        spec={{
          kind: 'column',
          categories: ['Q1', 'Q2', 'Q3', 'Q4'],
          series: [{ name: 'Revenue', values: [120, 180, 240, 300], color: '#E5481F' }],
        }}
      />
    </Slide>
  </Presentation>
);
```

Export a `Presentation` as the module's default export. The default canvas is
16:9, approximately **13.333 × 7.5 inches**. Positions and dimensions (`x`, `y`,
`width`, `height`) are in **inches**; font sizes and stroke widths are in **points**.
Child order is drawing order. Geometry is explicit; there is no automatic layout.

## Native elements

| Element | Main inputs |
| --- | --- |
| `Presentation` | Optional source PPTX bytes, `size`, `theme`, `mode`. |
| `Slide` | Optional `background`, `notes`, `layout`, source `from`, or edit `target`. |
| `Text` | Required bounds; literal children or rich `paragraphs`; text formatting such as `size`, `bold`, `color`; `bullets` and `paragraphSpacing`; a `bullet` and `level` per entry of `paragraphs`. |
| `Shape` | Required bounds and `preset`; fill, stroke, effects, optional text with `align` and `anchor`. |
| `Line` | End points `x1`, `y1`, `x2`, `y2`; `color` and `width`. |
| `Group` | Two or more visual elements that move and resize as one object; optional `name`. |
| `Image` | Required bounds and byte `data`; optional format and fit. |
| `Media` | Required bounds; `kind` `video` / `audio` with byte `data`, or `online` with a `url`; optional `poster`. |
| `Chart` | Required bounds and core `ChartSpec` in `spec`. |
| `Table` | Required bounds and `rows` of strings or cell objects (`text` or rich `paragraphs`, `colSpan`, `rowSpan`); column widths, row heights, cell/header styles, stripe fill, and a per-cell `styleCell` callback. Cell styles cover fill, text format, anchor, alignment and borders. |
| `Fill` | Existing shape `target`, replacement text children, optional `format` and `autoFit`. |
| `Remove` | Existing shape `target`. |
| `Raw` | Deferred callback for public core APIs; optional explicit scope. |

Use editor completion on each element to see its typed props. The
[core API reference](/pptx/api) documents types such as `ChartSpec`
and `ParagraphSpec`; it is the function-level API, not a list of JSX components.

Reuse elements with ordinary TypeScript functions, arrays, fragments, conditions
and `.map()`. A separate high-level component library is not included. Images can
be loaded in the Node authoring workflow with
`readFile(new URL('./image.png', import.meta.url))`; pass the resulting bytes to
`Image` through `data`.

## Edit or compose a template

First run `npx --no-install office-pptx inspect template.pptx` in an initialized
project. It prints slide indices, part names, layouts, shape names and IDs.
Missing or ambiguous references are errors.

| Reference | Supported selectors |
| --- | --- |
| Slide | Zero-based `index`, exact `title`, or `part`. |
| Layout | Exact `name`, `type`, or `part`. |
| Shape | Exact `name`, `id`, or `placeholder` with optional `type` and/or `idx`. |

With `Presentation source={bytes}`, the default is `mode="edit"`. A
`Slide target={{ index: 0 }}` edits the original first slide while unmentioned
slides remain. `Fill` replaces only the selected shape's text; formatting changes
are explicit. Existing template masters and layouts remain in the package.

To deliberately replace the slide sequence, use compose mode:

```tsx
import { readFile } from 'node:fs/promises';
import { Presentation, Slide, Fill } from '@office-kit/pptx-dsl';

const source = await readFile(new URL('./template.pptx', import.meta.url));

export default (
  <Presentation source={source} mode="compose">
    <Slide from={{ index: 0 }}>
      <Fill target={{ name: 'Title 1' }}>Opening</Fill>
    </Slide>
    <Slide from={{ index: 0 }}>
      <Fill target={{ name: 'Title 1' }}>Closing</Fill>
    </Slide>
  </Presentation>
);
```

This produces two copies of the original first slide and removes the original
sequence. Replace `Title 1` with a real target. Source references always refer
to the original deck, and every rebuild loads the source fresh. Source decks keep
their original dimensions; `size` applies only to new presentations.

Preserving existing OOXML is different from exposing every feature as a typed
DSL element. Unknown content should remain in the package even if the preview
cannot render it. Cross-presentation imports are not offered as a lossless path.

## Raw escape hatch

Use `Raw` when the core library supports a capability that has no declarative
prop. It runs after normal construction, in declaration order, before compose
mode removes original slides. Callbacks can be async.

```tsx
import { setSlideTransition } from '@office-kit/pptx';
import { Presentation, Slide, Text, Raw } from '@office-kit/pptx-dsl';

export default (
  <Presentation>
    <Slide>
      <Text x={1} y={1} width={10} height={1} size={32}>Welcome</Text>
      <Raw
        scope="slide"
        apply={({ slide }) => {
          setSlideTransition(slide, { effect: 'fade', speed: 'med' });
        }}
      />
    </Slide>
  </Presentation>
);
```

`scope="presentation"`, `scope="slide"`, and `scope="shape"` require the
corresponding context and check nesting. Without scope, slide/shape handles are
optional. `Raw` executes trusted local code, as do other imports in the TSX file.
The static SVG preview does not play the transition in this example.

## Embedding compile() in your own build

An `office-pptx init` project comes with a build that records source locations and a
`check` script that runs `tsc --noEmit`. A host that calls `compile()` from its own
build has to arrange both.

- Build with the dev JSX transform (TypeScript `"jsx": "react-jsxdev"`, esbuild
  `jsx: 'automatic', jsxDev: true`). Only then does a `compile()` error start with
  `file:line:col <Element>:` for each enclosing element.
- Run `tsc` in strict mode on authored modules. The runtime ignores a prop it does
  not know, so type checking is the only thing that rejects one.
- `compile(root)` takes the root `Presentation` element and resolves to the core
  presentation; `savePresentation` from `@office-kit/pptx` gives the `.pptx` bytes.
  Template bytes go in through `<Presentation source={bytes}>`.

## Package responsibilities and current limits

| Package | Responsibility |
| --- | --- |
| `@office-kit/pptx` | Read, change, validate and serialize the PPTX/OOXML package. |
| `@office-kit/pptx-dsl` | Typed TSX elements and compilation to the core model. |
| `@office-kit/pptx-preview` | Rendering; separate from authoring and preservation. |
| `@office-kit/pptx-dev` | Node CLI: project creation, watch, viewer, inspection and export. |

The DSL is initial coverage, not complete PPTX coverage. Typed master/layout
creation, animations, transitions, connectors attached to shapes (`Line` is a
free-standing straight line), media playback, and merged or rich-text table
cells need additional elements or core work. Raw can use
available core functions, but does not count as typed declarative coverage.
