rlz-web-slides
v0.1.1
Published
Composable React slides, themes, an embedded player and standalone HTML export
Maintainers
Readme
Web Slides
A small set of React components for composing slides: a resolved theme, an embedded and fullscreen player, and flexible primitives. Demo slides live in src/examples and are used by the local Vite documentation.
Install
npm install rlz-web-slidesReact, React DOM, and Emotion are peer dependencies and are usually already present in a React application.
Develop
Development requires Node.js 22.12+ and npm.
npm install
npm start # documentation with a live demo
npm run dev # same as above
npm run demo # standalone presentation at /demo.html
npm run build # production site in dist/
npm test # library tests
npm run lint # Oxlint and formatting checks
npm run format # format source filesDocumentation is available at /; the standalone demo is at /demo.html. Use the player button or F to enter the native Fullscreen API. Browsers do not allow fullscreen to start on page load.
GitHub Pages
The .github/workflows/deploy-pages.yml workflow deploys the built documentation on pushes to main. After its first run, open Settings → Pages in the GitHub repository and choose GitHub Actions as the publishing source. The site will be available at https://<owner>.github.io/<repository>/.
Use
Consumer applications import from rlz-web-slides. Enable the Emotion JSX runtime in tsconfig.json to use the css prop:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
}
}import {
DecoratedSlide,
Presentation,
SlideNumber,
SlidesThemeProvider
} from 'rlz-web-slides'
const slides = [
<DecoratedSlide
headerLeft="My project"
footerLeft="September 2026"
footerRight={<SlideNumber />}
>
<h1>Start with the main idea.</h1>
<p>One thought per slide.</p>
</DecoratedSlide>
]
export function App() {
return (
<SlidesThemeProvider theme={{ colors: { 'accent-1': '#b8d7fa' } }}>
<Presentation slides={slides} />
</SlidesThemeProvider>
)
}Player
Presentation accepts slides: readonly ReactNode[]. embedded is the default mode; fullscreen fills the browser window. In native fullscreen, the controls hide and slides use the entire screen. initialSlide, onSlideChange(index), and controls set the initial index, receive slide changes, and configure the controls.
The player preserves the canvas aspect ratio with ResizeObserver. ← / →, Space, PageUp / PageDown, and Home / End work only in the focused player; inputs and editable elements keep their keyboard behavior. F enters native fullscreen and Esc exits it. Inactive slides stay mounted but are removed from focus navigation and the accessibility tree.
Components
Slide, DecoratedSlide, and Panel accept className and Emotion css; SlideNumber accepts css. External styles take precedence. The library does not modify body, global scrolling, or a page reset.
| Component | Purpose |
| ---------------- | ----------------------------------------------------------------------------------- |
| Slide | The themed canvas, without padding or utility areas |
| DecoratedSlide | A Slide with headerLeft, headerRight, footerLeft, and footerRight slots |
| Panel | A themed surface with a background, padding, corner radius, and configurable shadow |
| SlideNumber | The current slide number and total from Presentation context |
DecoratedSlide keeps headers and footers in normal flex flow while its central area fills the remaining height. Slots accept strings or arbitrary React nodes. Pass null to both slots of an area to omit it.
<DecoratedSlide
headerLeft="Team"
headerRight="Strategy"
footerLeft="Internal document"
footerRight={<SlideNumber css={{ fontWeight: 700 }} />}
>
<h1>The main idea</h1>
</DecoratedSlide>Drawing on a slide
Pass drawing to Slide or DecoratedSlide to show drawing controls at the top center. Annotations are local to the browser and tied to that slide instance: they do not modify children or appear in HTML export. The controls include an opaque pen, translucent highlighter, seven contrasting colors, a large eraser, and clear all. “Blank canvas” replaces the slide with a white surface; “Over slide” lightly dims the original slide.
<DecoratedSlide drawing headerLeft="Walkthrough">
<h1>Mark up important details while you present</h1>
</DecoratedSlide>Theme
SlidesThemeProvider accepts a fully optional SlidesThemeInput. useSlidesTheme() returns a resolved SlidesTheme and also works without a provider. resolveSlidesTheme(input) returns the same result outside React.
Nested providers inherit overrides. The palette has three accents: accent-1, accent-2, and accent-3, available as theme.colors['accent-1'] and so on. light and dark define the base surface colors, while textLight and textDark define their text colors. colord derives shades and culori determines contrast, including CSS OKLCH. CSS variables use compatible color-mix() output.
theme.backgrounds is one shared generator set for slides, panels, and custom surfaces. It provides solid(color?), gradient(color?), texture({ base, dot, size }), aurora({ base, lowerLeft, upperRight, center }), mesh({ base, colors }), grid({ base, line, size }), and spotlight({ base, light, position }). The option objects let visual treatments control their independent colors and geometry rather than reducing every background to one color.
Panel has a light surface by default. Pass a background generator through Emotion css to change it. It also supports shadow ('low' by default, 'medium', 'high', or false) and padding; when neither the prop nor css sets padding, it uses theme.spacings.half. The theme provides theme.shadows.low, theme.shadows.medium, and theme.shadows.high.
Alongside base theme.spacing and theme.radius, the resolved theme provides theme.spacings.tight, compact, half, comfortable, base, double and theme.radii.quarter, half, base, double. These values are recalculated when a base value changes, so components need not multiply spacing or radii manually.
Every background factory adds a contrasting color with its backgroundColor. Pass the result to css to override a background; an explicitly supplied external color always takes precedence.
import { Panel, Slide, useSlidesTheme } from 'rlz-web-slides'
import { colord } from 'colord'
function ResultSlide() {
const theme = useSlidesTheme()
const panelColor = colord(theme.colors['accent-1']).lighten(0.16).toHex()
return (
<Slide css={theme.backgrounds.gradient('accent-2')}>
<Panel css={theme.backgrounds.solid(panelColor)}>
<h2>Result</h2>
</Panel>
</Slide>
)
}Structure
src/theme.tsx SlidesThemeProvider, useSlidesTheme, resolveSlidesTheme
src/components/ Slide, Panel, and SlideNumber
src/player/ Presentation and its contexts
src/slides/ DecoratedSlide
src/examples/ Demo slides
src/docs/ One-page documentationThe former positioning primitives (Box, Row, Column, Text, Image, NumberedList) and the TopBottom, TwoColumns, Sidebar, and TwoPanels templates have been removed. Compose custom layouts with ordinary HTML elements and Emotion css inside Slide or DecoratedSlide.
