Hyperiux Vault

Block Transition

Component 21

About

Split-block transition: rows of blocks close in from both sides, cover the view while its content swaps, then part to reveal the next one. Trigger it from any button by changing a key. Optional content scale and blur, theme-aware color, reduced-motion fade.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Block Transition to your project and fits it to your theme.

Code

How Block Transition is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import { useState } from "react";
import BlockTransition from "@/components/ui/block-transition";

const settings = {
  rows: 5,
  duration: 1,
  enableContentShift: false,
  color: "#0a0a0a",
};

const PAGES = [
  {
    label: "Page one",
    eyebrow: "01",
    title: "Close the curtain, change the scene.",
    body: "Rows of blocks slide in from both sides, meet in the middle, then part again to reveal the next page.",
    cta: "Go to page two",
  },
  {
    label: "Page two",
    eyebrow: "02",
    title: "Scene two.",
    body: "Turn on Content Shift in the controls to add a soft scale and blur to the page as it changes.",
    cta: "Back to page one",
  },
];

function ArrowIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="h-4 w-4">
      <path d="M5 12h14M13 6l6 6-6 6" />
    </svg>
  );
}

function Page({ index, onNavigate }: { index: number; onNavigate: (index: number) => void }) {
  const page = PAGES[index];

  return (
    <div
      className={`flex min-h-screen w-full flex-col text-foreground ${
        index === 1 ? "bg-muted" : "bg-background"
      }`}
    >
      <header className="flex items-center justify-between px-6 py-5 sm:px-10">
        <span className="text-base font-semibold tracking-tight">Acme</span>
        <nav aria-label="Pages" className="flex gap-1">
          {PAGES.map((item, itemIndex) => (
            <button
              key={item.label}
              type="button"
              aria-current={itemIndex === index ? "page" : undefined}
              onClick={() => onNavigate(itemIndex)}
              className={`rounded-full px-3 py-1.5 text-sm font-medium outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring ${
                itemIndex === index ? "text-foreground" : "text-muted-foreground hover:text-foreground"
              }`}
            >
              {item.label}
            </button>
          ))}
        </nav>
      </header>

      <main className="flex flex-1 flex-col items-center justify-center gap-6 px-6 pb-16 text-center">
        <span className="font-mono text-xs tracking-[0.3em] text-muted-foreground">{page.eyebrow}</span>
        <h1 className="max-w-[16ch] text-4xl font-semibold leading-[1.05] tracking-tight sm:text-6xl">
          {page.title}
        </h1>
        <p className="max-w-md text-sm leading-relaxed text-muted-foreground sm:text-base">{page.body}</p>
        <button
          type="button"
          onClick={() => onNavigate(index === 0 ? 1 : 0)}
          className="mt-2 inline-flex items-center gap-2 rounded-full bg-primary px-5 py-2.5 text-sm font-medium text-primary-foreground outline-none transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background active:scale-95"
        >
          {page.cta}
          <ArrowIcon />
        </button>
      </main>
    </div>
  );
}

export default function BlockTransitionDemo(props: Partial<typeof settings>) {
  const s = { ...settings, ...props };
  const [page, setPage] = useState(0);

  return (
    <BlockTransition
      transitionKey={page}
      rows={s.rows}
      duration={s.duration}
      enableContentShift={s.enableContentShift}
      // Hex keeps a color picker in the Controls panel; until it's changed, the
      // component's own theme-aware default is used.
      color={s.color === settings.color ? undefined : s.color}
    >
      <Page index={page} onNavigate={setPage} />
    </BlockTransition>
  );
}

Dependencies

More by Hyperiux Vault

View all
  • Product Timeline

    Product Timeline

    2.3K
  • Stack Spread

    Stack Spread

    1.3K
  • Arrow Fill Button

    Arrow Fill Button

    912
  • Interactive List Preview

    Interactive List Preview

    867
  • Shiny Button

    Shiny Button

    742
  • Circular Split Roll

    Circular Split Roll

    637
  • Zoom Slider

    Zoom Slider

    429
  • Stack Loader

    Stack Loader

    371