Creating a Slide repository with Astro and Reveal.js
Reveal.js is a powerful tool for creating beautiful slide presentations using web technologies. However, managing individual repositories for each presentation becomes increasingly difficult as the collection expands. Enter Astro - the modern framework for content-driven websites. Astro delivers zero-JS-by-default, Islands Architecture for partial hydration, file-based routing, TS and multi-framework (React, Vue, Svelte, etc.) support. These features make it a perfect tool for what we'll be building. Goal We'll create an Astro website that: Centralizes all Reveal.js presentations in one place Provides a main page listing all available slides Supports multiple UI frameworks for interactive demos Let's Get Started! 1. Create an Astro Project First, let's scaffold a new Astro project with pnpm: pnpm create astro@latest 2. Create a Reveal.js Layout We'll create a reusable layout component for our slides: --- export interface Props { title: "string;" authors: string[]; description?: string; } import Layout from "./BaseLayout.astro"; import "reveal.js/dist/reveal.css"; import "reveal.js/plugin/highlight/monokai.css"; const { title, authors, description } = Astro.props; --- {/* See Layout at https://github.com/hnrq/slides/blob/main/src/layouts/SlideLayout.astro */} {description && } {authors.map((author) => )} import Reveal from "reveal.js"; import Highlight from "reveal.js/plugin/highlight/highlight.esm.js"; let deck = new Reveal({ plugins: [Highlight] }); deck.initialize(); 3. Creating Individual Slides Each slide is an .astro file in src/slides with frontmatter metadata: --- import CSSPropertyDemo from "./components/CSSPropertyDemo.svelte"; export const title = "CSS Flexbox"; export const authors = ["Henrique Ramos"]; export const publishedAt = "2025-01-27"; export const description = "Do you even flex?"; export const draft = true; --- What is Flexbox? One-dimensional layout model Distributes space along a single direction Powerful alignment capabilities 4. Leveraging Astro Islands One of the coolest features of Astro is being any UI framework for interactive components. For example, we can create a Svelte component for demonstrating CSS properties and append it to the slide. 5. Building the Homepage Since Astro doesn't yet support .astro content collections, we'll create a utility to load and validate our slides: import type { AstroInstance } from "astro"; import { type } from "arktype"; type Opts = { files: Record; schema: type; }; const astroPageType = type({ "draft?": "boolean", }); const getAstroPages = ({ files, schema, }: Opts) => { // ... implementation }; export default getAstroPages; And create a slides getter: const schema = type({ title: "string", description: "string", authors: "string[]", publishedAt: "string", }); type Slide = AstroInstance & typeof schema.infer & { [key: string]: unknown }; export const getSlides = () => getAstroPages({ files: import.meta.glob( ["@slides/**/index.astro", "@slides/*.astro"], { eager: true }, ), schema, }); Finally, implement the homepage: --- import { getSlides } from "@utils/getSlides"; const slides = getSlides() .filter(({ draft }) => !draft) .sort((c1, c2) => (c1.title > c2.title ? -1 : 1)); --- Slides Here you can find a list of all available slides: { slides.map((slide) => ( {slide.title} {slide.description} {new Date(slide.publishedAt).toLocaleDateString()} )) } Future Improvements Here are some ideas to improve: Make Reveal.js plugins configurable through props Improve code block highlighting in client-side components Add presentation themes and customization options Conclusion By combining Astro with Reveal.js, we've created a modern, maintainable system for managing presentations, allowing us to centralize and enhance our slides with Interactivity Islands. What do you think? Share your thoughts and ideas in the comments below! Live demo and Code. Note: This implementation is a starting point - feel free to customize and extend it based on your needs.

Reveal.js is a powerful tool for creating beautiful slide presentations using web technologies. However, managing individual repositories for each presentation becomes increasingly difficult as the collection expands.
Enter Astro - the modern framework for content-driven websites. Astro delivers zero-JS-by-default, Islands Architecture for partial hydration, file-based routing, TS and multi-framework (React, Vue, Svelte, etc.) support. These features make it a perfect tool for what we'll be building.
Goal
We'll create an Astro website that:
- Centralizes all Reveal.js presentations in one place
- Provides a main page listing all available slides
- Supports multiple UI frameworks for interactive demos
Let's Get Started!
1. Create an Astro Project
First, let's scaffold a new Astro project with pnpm
:
pnpm create astro@latest
2. Create a Reveal.js Layout
We'll create a reusable layout component for our slides:
---
export interface Props {
title: "string;"
authors: string[];
description?: string;
}
import Layout from "./BaseLayout.astro";
import "reveal.js/dist/reveal.css";
import "reveal.js/plugin/highlight/monokai.css";
const { title, authors, description } = Astro.props;
---
{/* See Layout at https://github.com/hnrq/slides/blob/main/src/layouts/SlideLayout.astro */}
{title}>
slot="head">
{description && name="description" content={description} />}
{authors.map((author) => name="author" content={author} />)}
class="reveal">
class="slides"> />
import Reveal from "reveal.js";
import Highlight from "reveal.js/plugin/highlight/highlight.esm.js";
let deck = new Reveal({ plugins: [Highlight] });
deck.initialize();
3. Creating Individual Slides
Each slide is an .astro
file in src/slides
with frontmatter metadata:
---
import CSSPropertyDemo from "./components/CSSPropertyDemo.svelte";
export const title = "CSS Flexbox";
export const authors = ["Henrique Ramos"];
export const publishedAt = "2025-01-27";
export const description = "Do you even flex?";
export const draft = true;
---
What is Flexbox?
One-dimensional layout model
Distributes space along a single direction
Powerful alignment capabilities
4. Leveraging Astro Islands
One of the coolest features of Astro is being any UI framework for interactive components. For example, we can create a Svelte component for demonstrating CSS properties and append it to the slide.
5. Building the Homepage
Since Astro doesn't yet support .astro
content collections, we'll create a utility to load and validate our slides:
import type { AstroInstance } from "astro";
import { type } from "arktype";
type Opts<T extends Record<string, unknown>> = {
files: Record<string, T>;
schema: type;
};
const astroPageType = type({
"draft?": "boolean",
});
const getAstroPages = <T extends Record<string, unknown> & AstroInstance>({
files,
schema,
}: Opts<T>) => {
// ... implementation
};
export default getAstroPages;
And create a slides getter:
const schema = type({
title: "string",
description: "string",
authors: "string[]",
publishedAt: "string",
});
type Slide = AstroInstance & typeof schema.infer & { [key: string]: unknown };
export const getSlides = () =>
getAstroPages<Slide>({
files: import.meta.glob<true, string, Slide>(
["@slides/**/index.astro", "@slides/*.astro"],
{ eager: true },
),
schema,
});
Finally, implement the homepage:
---
import { getSlides } from "@utils/getSlides";
const slides = getSlides()
.filter(({ draft }) => !draft)
.sort((c1, c2) => (c1.title > c2.title ? -1 : 1));
---
Slides
Here you can find a list of all available slides:
{
slides.map((slide) => (
href={`/${slide.id}`}>
{slide.title}
{slide.description}
{new Date(slide.publishedAt).toLocaleDateString()}
))
}
Future Improvements
Here are some ideas to improve:
- Make Reveal.js plugins configurable through props
- Improve code block highlighting in client-side components
- Add presentation themes and customization options
Conclusion
By combining Astro with Reveal.js, we've created a modern, maintainable system for managing presentations, allowing us to centralize and enhance our slides with Interactivity Islands.
What do you think? Share your thoughts and ideas in the comments below!
Note: This implementation is a starting point - feel free to customize and extend it based on your needs.