Hero sequence
The title, the lead and the buttons of a hero enter one after the other. Each part has its own Reveal, and each delay is larger than the previous one.
Build pages that feel alive
Reveal animations for React, Vue, Astro and plain JavaScript.
Your system reduces motion, so the preview does not animate. The code still follows your choices.
import { Reveal } from "@awesome-reveal/react";import { slide } from "@awesome-reveal/react/keyframes";
export function Hero({ title, lead }) { return ( <header className="hero"> <Reveal as="h1" keyframes={slide()}>{title}</Reveal> <Reveal as="p" keyframes={slide()} delay={200}>{lead}</Reveal> <Reveal className="actions" keyframes={slide()} stagger={80} delay={400}> <a href="/start">Get started</a> <a href="/docs">Read the docs</a> </Reveal> </header> );}<script setup>import { Reveal } from "@awesome-reveal/vue";import { slide } from "@awesome-reveal/vue/keyframes";
defineProps(["title", "lead"]);</script>
<template> <header class="hero"> <Reveal as="h1" :keyframes="slide()">{{ title }}</Reveal> <Reveal as="p" :keyframes="slide()" :delay="200">{{ lead }}</Reveal> <Reveal class="actions" :keyframes="slide()" :stagger="80" :delay="400"> <a href="/start">Get started</a> <a href="/docs">Read the docs</a> </Reveal> </header></template>---import { Reveal } from "@awesome-reveal/astro";import { slide } from "@awesome-reveal/astro/keyframes";
const { title, lead } = Astro.props;---
<header class="hero"> <Reveal as="h1" keyframes={slide()}>{title}</Reveal> <Reveal as="p" keyframes={slide()} delay={200}>{lead}</Reveal> <Reveal class="actions" keyframes={slide()} stagger={80} delay={400}> <a href="/start">Get started</a> <a href="/docs">Read the docs</a> </Reveal></header><header class="hero"> <h1>Build pages that feel alive</h1> <p>Reveal animations for React, Vue, Astro and plain JavaScript.</p> <div class="actions"> <a href="/start">Get started</a> <a href="/docs">Read the docs</a> </div></header>import { reveal } from "@awesome-reveal/core";import { slide } from "@awesome-reveal/core/keyframes";
const [title, lead, actions] = document.querySelectorAll(".hero > *");
reveal(title, { keyframes: slide(),});reveal(lead, { keyframes: slide(), delay: 200,});reveal(actions, { keyframes: slide(), stagger: 80, delay: 400,});/* Transforms do not apply to inline elements. */.actions { display: flex; gap: 0.5rem;}Why a Reveal for each part
Section titled “Why a Reveal for each part”One Reveal with stagger on the whole hero would animate the buttons as one element. With a Reveal for each part, the buttons get their own stagger, and each part can have its own keyframes.
- The delays work because the parts enter the viewport together. Above the fold, they enter when the page loads. A
Revealthat enters later starts its delay at that time. - Keep the sequence short. The last part starts two gaps after the first one, so a long gap makes visitors wait for the buttons.
- The title is often the Largest Contentful Paint (LCP) element. Chrome skips elements at opacity 0 when it measures LCP, so a hidden title can delay LCP. If the title is your LCP element, keep it out of the sequence.
Next steps
Section titled “Next steps”Text animationReveal a headline word by word or letter by letter.
OptionsDuration, delay, stagger and the viewport options.
AccessibilityReduced motion, screen readers and pages without JavaScript.
Getting startedInstall the package for your framework.
Awesome Reveal is free and open source. Sponsor it on GitHub.