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 */}
<Layout {title}>
<Fragment slot="head">
{description && <meta name="description" content={description} />}
{authors.map((author) => <meta name="author" content={author} />)}
</Fragment>
<div class="reveal">
<div class="slides"><slot /></div>
</div>
</Layout>
<script>
import Reveal from "reveal.js";
import Highlight from "reveal.js/plugin/highlight/highlight.esm.js";
let deck = new Reveal({ plugins: [Highlight] });
deck.initialize();
</script>
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;
---
<section>
<h2>What is Flexbox?</h2>
<ul>
<li>One-dimensional layout model</li>
<li>Distributes space along a single direction</li>
<li>Powerful alignment capabilities</li>
</ul>
</section>
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));
---
<h1>Slides</h1>
<p>Here you can find a list of all available slides:</p>
{
slides.map((slide) => (
<a href={`/${slide.id}`}>
<h2>{slide.title}</h2>
<p>{slide.description}</p>
<small>{new Date(slide.publishedAt).toLocaleDateString()}</small>
</a>
))
}
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.
Top comments (0)