Skip to content

Authoring guide

The fastest way to learn the API is to build a deck. Open /showcase/slides in another tab — every example below maps directly to a slide in that deck.

1. Title slide

<Slide layout="title">
<Title>helix-ui slides</Title>
<Subtitle>tokens · components · pptx export</Subtitle>
</Slide>

The 'title' layout centers the title and subtitle vertically with generous side margins. Add a colored band by stacking a <Frame> with a fill underneath:

<Slide layout="title">
<Frame x={0} y={0} w={13.333} h={2.4} fill="brand" />
<Frame x={0.7} y={0.7} w={6} h={1}>
<SlideText size={14} weight="semibold" color="paper">
helix-ui · slides
</SlideText>
</Frame>
<Title>An AI-friendly design system, now for slides.</Title>
<Subtitle>Build presentations as React components. Export to PPTX.</Subtitle>
</Slide>

2. Bulleted content

<Slide layout="content">
<Title>Why slides as components?</Title>
<Bullets type="check" size={20}>
<Bullet>Same tokens as the rest of helix-ui.</Bullet>
<Bullet>Diffable, reviewable, programmatic.</Bullet>
<Bullet>Render anywhere — DOM preview, .pptx export.</Bullet>
</Bullets>
</Slide>

The 'content' layout reserves the top ~13% for the title and the rest for the body. The <Bullets> component falls into the body slot when not wrapped in a frame.

3. Two-column comparison

<Slide layout="two-column">
<Title>The deck is data, the renderer is a detail.</Title>
<Frame x={0.5} y={1.7} w={6} h={5.3}>
<Heading level={3}>Web preview</Heading>
<Bullets type="arrow">
<Bullet>Auto-scales to any container width</Bullet>
<Bullet>Speaker mode with keyboard navigation</Bullet>
</Bullets>
</Frame>
<Frame x={6.833} y={1.7} w={6} h={5.3}>
<Heading level={3}>PPTX export</Heading>
<Bullets type="arrow">
<Bullet>
One async call:{' '}
<SlideText font="mono" size={15}>
exportToPptx(deck)
</SlideText>
</Bullet>
<Bullet>Native PPTX shapes, tables, and charts</Bullet>
</Bullets>
</Frame>
</Slide>

The 'two-column' layout exposes bodyLeft and bodyRight placeholders, but explicit <Frame>s give you full control over column widths and gaps.

4. Native PPTX charts

<Slide layout="content">
<Title>Charts export as real PowerPoint charts.</Title>
<Frame x={0.5} y={1.5} w={6.2} h={5.5}>
<SlideChart
type="area"
title="Weekly sessions"
data={{
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
datasets: [
{ label: 'Web', data: [320, 410, 380, 520, 600, 540, 640], color: 'brand' },
{ label: 'Mobile', data: [180, 240, 220, 310, 360, 410, 480], color: 'success' },
],
}}
/>
</Frame>
<Frame x={6.9} y={1.5} w={5.9} h={5.5}>
<SlideChart
type="doughnut"
data={{ labels: ['A', 'B', 'C'], datasets: [{ label: 'mix', data: [3, 5, 2] }] }}
/>
</Frame>
</Slide>

The DOM rendering uses pure SVG (zero charting peer dependency). The exporter emits a native PowerPoint chart so end users can edit the data right inside PowerPoint.

5. Data-driven generation

The whole point of authoring slides as React is that they’re functions of data. Build a slide per item:

function ProductOverview({ products }: { products: Product[] }) {
return (
<Deck size="16:9" exportFileName="catalog.pptx">
<Slide layout="title">
<Title>{`Catalog · ${products.length} products`}</Title>
</Slide>
{products.map((p) => (
<Slide key={p.id} layout="image-right">
<Title>{p.name}</Title>
<SlideImage src={p.heroUrl} alt={p.name} />
<Bullets type="check">
{p.features.map((f) => (
<Bullet key={f}>{f}</Bullet>
))}
</Bullets>
<Notes>{p.salesNotes}</Notes>
</Slide>
))}
</Deck>
);
}
await exportToPptx(<ProductOverview products={data} />);

That’s the headline use case for @helix-ui/slides — programmatic decks.

6. Diagrams from primitives

A flow diagram is a few <SlideShape>s plus connector lines:

<Slide layout="content">
<Title>How a request flows</Title>
{STEPS.map((step, i) => (
<Frame key={step} x={0.5 + i * 3.0} y={3.5} w={2.6} h={1.2}>
<SlideShape
kind="roundRect"
radius={0.12}
fill={i === STEPS.length - 1 ? 'success' : 'brand'}
label={step}
labelStyle={{ color: 'paper', weight: 'semibold', size: 16 }}
/>
</Frame>
))}
{STEPS.slice(0, -1).map((_, i) => (
<SlideShape
key={i}
kind="arrowRight"
x={0.5 + i * 3.0 + 2.6}
y={4.0}
w={0.4}
h={0.2}
fill="neutral"
/>
))}
</Slide>

7. Tables

<Slide layout="content">
<Title>How it maps to PPTX</Title>
<Frame x={0.5} y={1.6} w={12.333} h={5.4}>
<SlideTable
header={['Component', 'PPTX equivalent', 'Notes']}
rows={[
['<Slide>', 'sld', 'One slide per element'],
['<Frame>', 'sp (group bounds)', 'Children inherit x/y/w/h'],
['<SlideShape>', 'sp prstGeom', 'Twenty preset shapes mapped 1:1'],
['<SlideChart>', 'graphicFrame chart', 'Editable PowerPoint chart'],
]}
colWidths={[3.4, 3.6, 5.0]}
/>
</Frame>
</Slide>

Tips

  • Always wrap floating content in a <Frame> when a layout doesn’t already place it. Frames make the export deterministic.
  • Use theme color refs ('brand', 'success') instead of hex literals whenever possible — your decks pick up live theme changes for free.
  • Keep speaker notes in <Notes>, not in commented-out JSX. They survive the PPTX round-trip.
  • Inline images are best for portability. The exporter does this for you in the browser; in node, set path: 'http(s)://...' and the pptxgenjs runtime resolves it.