Slides
A deck you can edit, reorder and present: a filmstrip, a stage, speaker notes, a grid of every slide and a full screen show with a presenter view, all drawn from one Slide canvas.
Installation#
Usage#
The deck is data: an array of items, each with an id and the slide to draw. Build each slide with Slide, keep the array in state and hand back the new one from onSlidesChange. The same element renders as a thumbnail, on the stage and full screen, scaled each time.
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Anatomy#
import {
Slides,
SlidesToolbar,
SlidesTitle,
SlidesPrevious,
SlidesCounter,
SlidesNext,
SlidesViewToggle,
SlidesPresent,
SlidesRail,
SlidesStage,
SlidesNotes,
SlidesGrid,
SlidesShow,
SlidesPresenterView,
} from "@/components/ui/slides"Reorder#
Drag a thumbnail up or down the rail. The slide comes up with you, the others step aside to open a soft footprint where it will land, and it settles there when you let go. From the keyboard, hold Alt and use the arrows. Escape cancels a drag. Right click a slide, in the rail or the grid, to present from it, duplicate it (⌘D), move it or delete it (⌫).
Grid#
The grid shows every slide at once for a look at the whole story. Pick one and it grows back into the stage from where it sat in the grid; open the grid again and it shrinks back to its spot.
Present#
SlidesShow takes the screen from the current slide. The arrows, Space and Page Down move on; going forward pushes the next slide in from the right and going back brings the last one in from the left, so the motion always says which way you went. With reduced motion the slides fade instead. The controls sit in a corner and step aside when the pointer rests; their shortcuts are in their tooltips.
Presenter view#
The speaker's screen: the current slide large, the next one small, the notes in a size you can read from a step back, and how long you have been talking. Press P during the show to switch to it, or render it on its own for a second window.
Read only#
Leave out onSlidesChange to show a deck someone else owns: the rail still selects but does not drag, and the notes read but do not edit.
API reference#
Slides
The deck and the context every part reads. It lays its parts out on a grid, so any of them can be left out. Every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| slides* | SlidesItem[] | - | The deck. Each item is { id, content, title?, notes? }, where content is usually a Slide. |
| onSlidesChange | (slides: SlidesItem[]) => void | - | Called with the new deck after a reorder or a notes edit. Without it the deck is read only: the rail does not drag and the notes do not edit. |
| value | string | - | The id of the current slide, controlled. |
| defaultValue | string | the first id | The current slide when uncontrolled. |
| onValueChange | (id: string) => void | - | Called when the current slide changes. |
| view | "edit" | "grid" | - | Rail and stage, or every slide in a grid. Controlled. |
| defaultView | "edit" | "grid" | "edit" | The view when uncontrolled. |
| onViewChange | (view) => void | - | Called when the view changes. |
| presenting | boolean | - | Whether the full screen show is open. Controlled. |
| defaultPresenting | boolean | false | Opens the show on mount when uncontrolled. |
| onPresentingChange | (presenting: boolean) => void | - | Called when the show opens or closes, including when the viewer leaves full screen. |
| aspectRatio | number | 16 / 9 | The ratio the stage, the show and the presenter view fit the slide to. Match it to the Slide size. |
| Data attribute | Description |
|---|---|
| data-view | edit or grid. |
SlidesToolbar
A row across the top for the title and the controls.
SlidesTitle
The deck's name. It takes the free space, so the controls after it sit at the end of the toolbar.
SlidesCounter
3 / 7 in tabular numerals, read as "Slide 3 of 7".
SlidesPrevious
Goes back one slide. Takes every Button prop except iconOnly and children.
SlidesNext
Goes forward one slide. Takes every Button prop except iconOnly and children.
SlidesViewToggle
Switches between the editor and the grid. Takes every Button prop except iconOnly and children.
SlidesPresent
Opens the show from the current slide. A primary Button; children replace the label.
SlidesRail
The filmstrip: a numbered thumbnail per slide, vertical beside the stage and horizontal under it on a phone. It is a listbox, so the arrows move between slides and selection follows. While you drag, the other thumbnails step aside and a soft footprint marks where the slide will land.
| Data attribute | Description |
|---|---|
| data-dragging | Present while a thumbnail is being dragged. |
SlidesStage
The current slide, scaled to fit the space it is given at the deck's aspectRatio.
SlidesNotes
The speaker notes of the current slide. A plain textarea; read only when the deck has no onSlidesChange.
SlidesGrid
Every slide at once, shown in place of the rail and the stage while view is grid. Picking one opens it on the stage.
SlidesShow
The full screen show. Renders nothing until presenting is true, then takes the screen, pushes each slide in from the side you are heading, and draws a progress line along the bottom.
| Data attribute | Description |
|---|---|
| data-idle | Present after a few seconds without the pointer moving, when the controls and the cursor hide. |
SlidesPresenterView
What the speaker sees: the current slide, the next one, the notes, an elapsed timer and the counter. Inside the show, P swaps to it; on its own it renders inline.
Slide#
One presentation slide, laid out on a fixed 1920 by 1080 canvas and scaled to whatever box it sits in, so it reads the same as a thumbnail and full screen. It installs on its own: a slide in a card, an email or a share image needs no deck.
Installation#
Usage#
Give the slide a width and write everything inside in canvas pixels. It follows the theme like the rest of the page, so a deck turns dark with the app.
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Anatomy#
import {
Slide,
SlideEyebrow,
SlideTitle,
SlideText,
SlideList,
SlideImage,
SlideFooter,
SlideNumber,
} from "@/components/ui/slide"Layouts#
Seven arrangements of the same parts. The layout decides where they go and which ink they use; you only choose the parts.
Any size#
The canvas never reflows: a 128px thumbnail and a full screen show draw the same picture, so a filmstrip always shows what the audience will see.
Aspect ratio#
Set width and height for a different canvas. In a deck, pass the same ratio to Slides so the stage fits it.
API reference#
Slide
The frame and its canvas. The frame takes the width it is given and the canvas inside scales to fill it, so type and spacing are written once, in canvas pixels. Every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| layout | "title" | "section" | "content" | "split" | "image" | "quote" | "blank" | "content" | Where the parts go. section inverts the colours, split puts a SlideImage on the right half, image lays it under everything with a scrim, blank adds no padding. |
| width | number | 1920 | The canvas width in pixels. |
| height | number | 1080 | The canvas height in pixels. Together with width it sets the frame's aspect ratio. |
| canvasClassName | string | - | Classes for the canvas, for a composition the layouts do not cover. |
| Data attribute | Description |
|---|---|
| data-layout | The layout. |
| data-ready | Present once the canvas has measured its frame. The canvas stays hidden until then, so it never flashes at the wrong size. |
| CSS variable | Description |
|---|---|
| --slide-scale | Frame width over canvas width, written on the frame as it resizes. |
| --slide-ink-2 | The reading ink of the text and list. Each layout sets it for its own ground. |
| --slide-ink-3 | The quiet ink of the eyebrow and footer. |
SlideEyebrow
A short label above the title, in capitals.
SlideTitle
The slide's heading, an h2. It balances its lines and grows on title and section slides.
SlideText
A paragraph in the reading ink, held to a comfortable measure.
SlideList
A ul of points, each li with a soft round bullet.
SlideImage
A photo in a rounded frame with an edge ring. On split it fills the right half, on image it covers the slide.
| Prop | Type | Default | Description |
|---|---|---|---|
| src* | string | - | The image URL. |
| alt* | string | - | What the photo shows. |
SlideFooter
A quiet row along the bottom, for the deck name and the number.
SlideNumber
The slide's position. Inside Slides it fills itself in; on its own, pass the number as children.
| Prop | Type | Default | Description |
|---|---|---|---|
| total | boolean | false | Reads 3 / 7 instead of 3. |