Using Pagefold with Astro
Add page transitions to an Astro site, with a layout, a script and the plugins you need.
Astro builds pages that are plain HTML, which is what Pagefold expects. This documentation site is built exactly like this, and it navigates with Pagefold.
1. The layout
Put what changes in an element with an id, and what stays outside it:
---
// src/layouts/Base.astro
import 'pagefold/css/fade.css'
---
<html lang="en">
<head>
<title>{title}</title>
<meta name="description" content={description} />
</head>
<body>
<header><!-- stays --></header>
<main id="pagefold" class="transition-fade">
<slot />
</main>
</body>
</html>
<script>
import Pagefold from 'pagefold'
import PagefoldHead from 'pagefold/head'
import PagefoldA11y from 'pagefold/a11y'
new Pagefold({
plugins: [new PagefoldHead({ awaitAssets: true }), new PagefoldA11y()],
})
</script>
Astro bundles that script for the browser. Because the layout is shared, it is on every page and runs once.
What happens on each click
<head> title, description, styles <header> <main id="pagefold"> home <head> merged by Head replaced <header> untouched <main id="pagefold"> about replaced 2. Why these plugins
- Head: Astro gives every page its own title, description and, depending on its styles, its own stylesheets. Without it, they would not change.
awaitAssets: truewaits for new stylesheets, so a page never appears unstyled. - A11y: announces the page and moves focus.
Add Preload, Scroll and Progress the same way.
Islands
Astro hydrates its framework components (“islands”) with small scripts that it writes into each page. Pagefold does not run scripts that arrive with new HTML, so add the Scripts plugin if you use islands:
import PagefoldScripts from 'pagefold/scripts'
new Pagefold({
plugins: [new PagefoldHead({ awaitAssets: true }), new PagefoldA11y(), new PagefoldScripts()],
})
What happens without it, checked with an Astro 6 site and Preact components:
| Directive | Without Scripts | With Scripts |
|---|---|---|
client:load | Works, but only because an earlier page had already defined it | Works |
client:idle | Never hydrates | Works |
client:visible | Never hydrates, even in view | Works |
client:media | Never hydrates | Works |
client:only | Nothing is rendered | Works |
The danger is that client:load on the first page makes everything look fine, and the others fail only when a visitor reaches them by clicking.
Things to know
- Do not use Astro’s own
<ClientRouter />at the same time. Both would try to handle the same clicks. - Scripts of your own pages. Astro publishes a page’s
<script>as a module, and the browser runs a module only once per document, even if its tag appears again. Code that must run on every visit belongs in a function that you call from thepage:viewhook. - Components that initialize in JavaScript need the pattern in Initializing components.
Checked
The islands table above was checked by building an Astro 6 site with Preact components and visiting its pages in a browser, with and without the plugin. That check is not part of this project’s automatic tests. The documentation site you are reading is the other check: the layout above, with Head, A11y, Scroll and Preload, was exercised in a browser. Links navigate without a reload, the title and description change, focus moves, the page is announced, the menu highlights the current page, and the back button works.