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>helixui 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">helixui · 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 helixui.</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 @helixui/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.