React app
A deck in a React app, with a live editor, a custom layout and a directive component.
This app shows a text area with Markdown, and a <Deck> of that Markdown.
Type in the text area: the deck changes, and shows the slide that has the
cursor. The second slide uses a custom layout. The third slide uses a
component for the :::callout directive.
A deck in a React app
Edit the Markdown: the deck changes as you type, and shows the slide under the cursor.
<Deck markdown={…} />renders the source- The deck stays on the same slide and step
Source
The app keeps the Markdown and the position of the deck in its state.
getSlideAtLine from @slidewright/core finds the slide that has the
cursor:
import { getSlideAtLine, parseDeck } from "@slidewright/core";
import { Deck, type DeckPosition } from "@slidewright/react";
import { useState } from "react";
import { components, layouts } from "./parts";
import slides from "./slides.md?raw";
export function App() {
const [markdown, setMarkdown] = useState(slides);
const [position, setPosition] = useState<DeckPosition>({ slide: 0, step: 0 });
// Show the slide under the cursor.
function follow(editor: HTMLTextAreaElement) {
const line = editor.value
.slice(0, editor.selectionStart)
.split("\n").length;
const slide = getSlideAtLine(parseDeck(editor.value), line);
if (slide !== position.slide) setPosition({ slide, step: 0 });
}
return (
<main className="app">
<textarea
aria-label="Deck source"
spellCheck={false}
value={markdown}
onChange={(event) => setMarkdown(event.target.value)}
onSelect={(event) => follow(event.currentTarget)}
/>
<Deck
markdown={markdown}
position={position}
onPositionChange={setPosition}
layouts={layouts}
components={components}
/>
</main>
);
}
The layout and the component:
import type { DirectiveComponents, Layout } from "@slidewright/react";
import type { ReactNode } from "react";
import "./parts.css";
/** `layout: sidebar`: the content, with `:::aside` in a column beside it. */
const Sidebar: Layout = ({ children, slots }) => (
<>
<div data-part="main">{children}</div>
<aside data-part="aside">{slots.aside}</aside>
</>
);
Sidebar.slots = ["aside"];
/** `:::callout{tone="warning"}`: a note that stands out. */
function Callout({
tone = "info",
children,
}: {
tone?: string;
children?: ReactNode;
}) {
return (
<div className="callout" data-tone={tone}>
{children}
</div>
);
}
export const layouts: Record<string, Layout> = { sidebar: Sidebar };
export const components: DirectiveComponents = { callout: Callout };
The CSS for the layout and the component:
/* `layout: sidebar`, arranged by its name. */
[data-layout="sidebar"] {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 2em;
}
[data-layout="sidebar"] [data-part="aside"] {
padding-left: 1.5em;
border-left: 2px solid var(--deck-border);
color: var(--deck-muted);
font-size: 0.85em;
}
/* `:::callout` */
.callout {
margin-bottom: 0.75em;
padding: 0.7em 1em;
border-radius: var(--deck-radius);
background: color-mix(in srgb, var(--deck-accent) 12%, transparent);
}
.callout[data-tone="warning"] {
background: color-mix(in srgb, #f59e0b 20%, transparent);
}
.callout > :last-child {
margin-bottom: 0;
}
The deck:
---
title: A deck in a React app
---
# A deck in a React app
Edit the Markdown: the deck changes as you type, and shows the
slide under the cursor.
- `<Deck markdown={…} />` renders the source
- The deck stays on the same slide and step
---
layout: sidebar
---
# A custom layout
`layout: sidebar` is a component from the `layouts` prop.
- The content goes in the main column
- `:::aside` goes beside it
:::aside
**Sidebar**
The layout lists `aside` in its `slots`, so this block goes here.
:::
---
# A custom component
:::callout
`:::callout` renders the `Callout` component from the `components` prop.
:::
:::callout{tone="warning"}
Attributes such as `tone="warning"` arrive as props.
:::
---
# Steps work as usual
- Press → in the deck to show the next step
<!-- step -->
- Edit this slide: the deck stays on this step
To start the app from a clone of the repository, run this command in the
examples folder:
bun run reactSee the @slidewright/react reference for all
the props of <Deck>.