Skip to main content

Reveal

Overview​

The Reveal component animates its content into view as it scrolls into the viewport, backed by IntersectionObserver. It's a lightweight, CSS-driven wrapper for "fade/slide/zoom in on scroll" effects on landing pages — no animation runtime dependency required.

Accessibility and progressive enhancement are built in, not opt-in:

  • Automatically skips the animation (renders the final, visible state immediately) when the user's OS requests prefers-reduced-motion: reduce.
  • Renders the final, visible state during server-side rendering and on the very first client render, so content is never hidden from crawlers or users if JavaScript never runs.
  • Falls back to the visible state immediately in environments without IntersectionObserver.

Import​

import { Reveal } from '@allxsmith/bestax-bulma';

Props​

PropTypeDefaultDescription
animation'fade' | 'fade-up' | 'fade-down' | 'slide-left' | 'slide-right' | 'zoom' | 'flip''fade-up'Animation style applied when the element enters the viewport.
delaynumber0Delay in milliseconds before the animation starts.
durationnumber600Animation duration in milliseconds.
thresholdnumber0.15Fraction (0-1) of the element that must be visible to trigger the reveal.
oncebooleantrueAnimate only the first time the element enters the viewport. If false, it re-animates on every entry/exit.
asReact.ElementType'div'Element or component to render as.
cascadebooleanfalseStagger direct children with an incrementing delay instead of animating this element as a single block.
cascadeIntervalnumber80Milliseconds added to each successive child's delay when cascade is set.
childrenReact.ReactNode—Content to reveal.
classNamestring—Additional CSS classes.
...All standard HTML and Bulma helper props(See Helper Props)

Usage​

Basic Reveal​

Fades a block up into view as it scrolls into the viewport.

function example() {
  return (
    <Reveal animation="fade-up">
      <Box>
        <Title size="4">Why bestax</Title>
        <Content>This box fades up into view once it's on screen.</Content>
      </Box>
    </Reveal>
  );
}

Rendering as a different element​

Use as to render the wrapper as a different tag or component, e.g. Section.

function example() {
  return (
    <Reveal animation="fade-up" as={Section}>
      <Title size="3">Why Grass Doctor</Title>
      <Content>Rendered as a `Section` instead of the default `div`.</Content>
    </Reveal>
  );
}

Animation styles​

animation accepts 'fade', 'fade-up', 'fade-down', 'slide-left', 'slide-right', 'zoom', and 'flip'.

function example() {
  return (
    <Columns isMultiline>
      <Column size="one-third">
        <Reveal animation="zoom">
          <Box>
            <Title size="5">zoom</Title>
          </Box>
        </Reveal>
      </Column>
      <Column size="one-third">
        <Reveal animation="flip">
          <Box>
            <Title size="5">flip</Title>
          </Box>
        </Reveal>
      </Column>
      <Column size="one-third">
        <Reveal animation="slide-left">
          <Box>
            <Title size="5">slide-left</Title>
          </Box>
        </Reveal>
      </Column>
    </Columns>
  );
}

Staggered (cascade) children​

Set cascade to stagger direct children of Reveal with an incrementing transitionDelay (cascadeInterval milliseconds apart), rather than animating the wrapper as a single block. Pass the individual items to stagger (e.g. Cards) directly as children, rather than a single nested layout component.

function example() {
  return (
    <Reveal
      animation="fade-up"
      cascade
      cascadeInterval={100}
      style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}
    >
      {['Fast', 'Accessible', 'Themeable'].map(feature => (
        <Card key={feature} style={{ flex: '1 1 160px' }}>
          <Card.Content>
            <Title size="5">{feature}</Title>
          </Card.Content>
        </Card>
      ))}
    </Reveal>
  );
}

Re-animating on every entry​

By default, Reveal only animates the first time it enters the viewport (once). Set once={false} to have it re-animate every time it scrolls in and out of view.

function example() {
  return (
    <Reveal animation="fade" once={false}>
      <Notification color="info">
        Scroll me out of view and back in to see this animate again.
      </Notification>
    </Reveal>
  );
}


Accessibility​

  • Reveal never removes content from the accessibility tree — it only animates opacity and transform, so screen reader users always have access to the content regardless of scroll position.
  • When the user's OS is set to reduce motion (prefers-reduced-motion: reduce), Reveal skips the animation entirely and renders the final, visible state immediately.
  • During server-side rendering and the first client render (before hydration effects run), Reveal renders the final, visible state — content is never hidden if JavaScript fails to load, ensuring crawlers and no-JS visitors always see the full page.