Skip to content

Astro

@awesome-reveal/astro has the Reveal component. It renders one element on the server, and animates it when it enters the viewport. Your pages need no client framework.

Terminal window
pnpm add @awesome-reveal/astro

The package needs Astro 6 or 7.

Import path Contents
@awesome-reveal/astro The Reveal component, and the RevealProps and RevealOptions types.
@awesome-reveal/astro/keyframes The built-in keyframes, defineKeyframes, and their types.

Reveal renders one element around its default slot. as sets the tag, and the default is div. Reveal gives its other attributes to that element:

---
import { Reveal } from "@awesome-reveal/astro";
import { fade, slide } from "@awesome-reveal/astro/keyframes";
---
<Reveal as="section" keyframes={slide()} class="hero" id="intro">
<h1>Welcome</h1>
</Reveal>
<Reveal as="article" keyframes={fade()} threshold={0.3}>
…
</Reveal>

Without keyframes, the element fades in and moves up, as with slide(). The keyframes factories run on the server, when Astro renders the page.

The children animate together. To animate them one after the other, use stagger.

Reveal is an Astro component. In a React island, use @awesome-reveal/react. In a Vue island, use @awesome-reveal/vue.

Reveal accepts the reveal options as props.

With when, your code controls the reveal, and nothing observes the viewport. threshold, rootMargin and once have no effect. For the other rules, such as the flash when when is true at the start, see Control the reveal manually.

Reveal writes its options into the options attribute of the <awesome-reveal> element, as JSON. To change them in the browser, set that attribute to new JSON. The new value replaces all the options, so merge your change into the current value. The change follows the option change rules. If the JSON is invalid when the element connects, the browser reports the error to the console, and the element reveals with the default options. If a later change is invalid, the previous options stay.

<button id="show">Show</button>
<Reveal id="details" when={false}>
…
</Reveal>
<script>
document.addEventListener("astro:page-load", () => {
document.querySelector("#show")?.addEventListener("click", () => {
const host = document.querySelector("#details")?.parentElement;
const options = JSON.parse(host?.getAttribute("options") ?? "{}");
host?.setAttribute("options", JSON.stringify({ ...options, when: true }));
});
});
</script>

Astro runs a bundled script once. The <ClientRouter /> fires astro:page-load on the first load and after each navigation, so the listener comes back on the new page. Without the router, run the code directly.

Reveal renders your element inside an <awesome-reveal> custom element:

<awesome-reveal options='{"duration":800}'>
<section class="hero" data-reveal="hidden">…</section>
</awesome-reveal>
  • The custom element reveals its first element child. Astro bundles the script that defines it, and adds the script once to the page.
  • The options go through JSON, so pass only plain values. The keyframes factories return plain values.
  • The custom element starts when it enters the page, so Reveal works with the <ClientRouter /> and with server islands.
  • A transition:persist element keeps its state, and does not play again after a navigation. You can put transition:persist on Reveal or on an ancestor.
  • On a page that the browser prerenders, the animation waits until the user opens the page.
  • Each Reveal writes its own copy of the options in the HTML. A preset adds about 100–200 bytes, spring() about 300 bytes, and a defineKeyframes factory about 3 kB. For a long list, use one Reveal with stagger.
  • The keyframes factories run on the server. If you call spring(), browsers without CSS linear() show the element with no animation. See Springs.

<awesome-reveal> has display: contents, so it adds no box to the layout. But it is still an element in the DOM:

  • Your element is the first child of <awesome-reveal>, so a sibling selector such as h2 + div or * + * does not match it. The selector can match <awesome-reveal>, but a margin on it has no effect. Give your element its own margin. For example, the Starlight content spacing does not apply to it.
  • Do not put Reveal directly in a <table>, <tbody> or <tr>. The HTML parser moves the <awesome-reveal> element out of the table. Put Reveal around the table, or inside a cell.
  • stagger cannot animate framework islands that are direct children, because <astro-island> also has display: contents. Put each island in an element.

Reveal works with the security.csp option of Astro. The server markup has no style attribute: data-reveal="hidden" and a stylesheet rule hide the element. Astro does not support security.csp with the <ClientRouter />.

The stylesheet rule that hides the element applies only in @media (scripting: enabled). When JavaScript is off, the content shows. You do not need the <noscript> style of the other packages.

The scripting media feature needs Chrome 120, Firefox 113 or Safari 17. In older browsers, the element shows until the script hides it. Then the reveal animation plays as usual.

Unrevealed elements stay invisible on a printed page. Add the print rule to your stylesheet. The hide rule of Reveal uses :where(), so it has no specificity, and the print rule wins.

@awesome-reveal/astro exports these types:

  • RevealProps<Tag>: the props of Reveal, where Tag is the tag in as. The attributes follow the tag.
  • RevealOptions: the reveal options.

@awesome-reveal/astro/keyframes exports the keyframes types, such as KeyframesFactory and SlideOptions. See Keyframes.