Era Strata Layout
An accordion layout that stacks eras or phases into horizontal strata — the expanded band opens vertically while the rest compress, and the content inside floats up with parallax.
This is a WebberUI Pro component
The install command below needs a licence to run; without one it returns 401.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add "https://webberui.com/r/era-strata-layout.en.json?t=<install token>"Era Strata Layout is a React vertical accordion timeline layout built with Motion and Tailwind CSS. Each era or phase is a horizontal band, and the expanded band can be switched by click, hover, or page scroll.
Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<EraStrataLayout/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
When to use
- Company history and milestones on an About page
- A phased walkthrough of a product's history or version evolution
- Chapters that advance by era in a brand story or long-form feature
- Ordered stages such as a course outline or an onboarding process
- Not a good fit: unrelated sections like Q&A or settings where several may be open at once; use Accordion instead
Installation
npx webberui@latest add "https://webberui.com/r/era-strata-layout.en.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/era-strata-layout.
Usage
import {
EraStrataLayout,
type EraStratumData,
} from "@/components/ui/era-strata-layout";
const eras: EraStratumData[] = [
{
id: "1998",
era: "1998",
title: "Founded in a garage",
summary: "Three people and one server.",
content: "The first version shipped late at night.",
accentClassName: "bg-amber-400 dark:bg-amber-500",
},
// ...
];
<EraStrataLayout items={eras} height={440} defaultActive={0} />;trigger switches how expansion is triggered: click (the default), hover to expand on hover, or scroll to advance stratum by stratum as the page scrolls.
// Advance on scroll: when scrolling inside a nested container, pass that container's ref to container
<EraStrataLayout items={eras} trigger="scroll" height={480} />Examples
Control the expanded band with external buttons
Pass active and onActiveChange to enter controlled mode and pair it with previous/next buttons (controlled mode applies to the click and hover triggers).
"use client";
import * as React from "react";
import { EraStrataLayout, type EraStratumData } from "@/components/ui/era-strata-layout";
export function CompanyHistory({ eras }: { eras: EraStratumData[] }) {
const [active, setActive] = React.useState(0);
return (
<div className="space-y-4">
<EraStrataLayout items={eras} active={active} onActiveChange={setActive} />
<div className="flex gap-2">
<button onClick={() => setActive((i) => Math.max(0, i - 1))}>Previous stage</button>
<button onClick={() => setActive((i) => Math.min(eras.length - 1, i + 1))}>
Next stage
</button>
</div>
</div>
);
}Expand on hover with custom content
content and summary accept any React node, so lists or images work; trigger="hover" expands a band on mouse hover or keyboard focus.
const roadmap: EraStratumData[] = [
{
id: "q1",
era: "Q1",
title: "Public beta",
summary: "Opened to 500 early users.",
content: (
<ul className="list-disc pl-5 text-sm">
<li>Accounts and team permissions</li>
<li>Basic report export</li>
</ul>
),
accentClassName: "bg-sky-500",
},
{
id: "q2",
era: "Q2",
title: "General availability",
summary: "Sign-up opened to everyone.",
accentClassName: "bg-emerald-500",
},
];
<EraStrataLayout items={roadmap} trigger="hover" height={360} collapsedSize={64} />Advance on scroll inside a nested scroll container
When scrolling happens inside its own overflow container rather than the page, pass that container's ref to container.
"use client";
import * as React from "react";
import { EraStrataLayout, type EraStratumData } from "@/components/ui/era-strata-layout";
export function ScrollPanel({ eras }: { eras: EraStratumData[] }) {
const panelRef = React.useRef<HTMLDivElement>(null);
return (
<div ref={panelRef} className="h-[480px] overflow-y-auto">
<EraStrataLayout items={eras} trigger="scroll" height={480} container={panelRef} />
</div>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | EraStratumData[] | — | Strata data, stacked top to bottom in order |
active | number | — | Controlled expanded index (applies in click / hover modes) |
defaultActive | number | 0 | Initial expanded index in uncontrolled mode |
onActiveChange | (index: number) => void | — | Fires when the expanded index changes |
trigger | "click" | "hover" | "scroll" | "click" | How expansion is triggered |
height | number | string | 440 | Total layout height (a number means px) |
collapsedSize | number | 72 | Height of a collapsed stratum / title bar (px) |
parallax | boolean | true | Whether the content floats up with parallax |
container | RefObject<HTMLElement | null> | — | Nested scroll container ref for scroll mode |
label | string | "Chronological Stratigraphy" | Accessible label |
className | string | — | Class on the outer container |
stratumClassName | string | — | Class applied to each stratum band |
EraStratumData
| Field | Type | Description |
|---|---|---|
id | string | Stable identifier, used as the accessibility anchor and the key |
era | ReactNode | Era / phase marker, still visible when collapsed |
title | ReactNode | Section title, still visible when collapsed |
summary | ReactNode | The one-line summary that floats up first on expand |
content | ReactNode | The main content that floats up with parallax on expand |
accentClassName | string | Accent color class for the stratum color bar on the left |
How it works
- The expanded stratum opens vertically on a spring transition while the rest compress back to
collapsedSizein sync, leaving only their title bars visible - Remaining space is distributed with flexbox
flex-grow, and exactly one stratum is expanded at a time; make sureheight≥collapsedSize × number of strata - Inside a stratum,
summaryandcontentfloat up in sequence from different starting offsets to create parallax layering; withparallax={false}only the fade in remains scrollmode extends the matching scroll height and pins to the viewport, mapping scroll progress onto the expanded stratum; clicking a stratum smoothly scrolls to it
Accessibility
- Each stratum title is a native
buttonwitharia-expandedandaria-controls, and the content area is arole="region"labeled by its title througharia-labelledby - The title bars use a roving tabindex: after
Tabmoves in,↑/↓(or←/→) move between strata,Home/Endjump to the first and last, andEnter/Spaceexpand - Collapsed content areas are marked
inertandaria-hidden, so neither the keyboard nor assistive technology wanders into them - When the user has "reduce motion" enabled at the system level, it becomes a fully expanded static list showing all the content at once, with no compression and no animation
FAQ
Does it work with the Next.js App Router?
Yes. The file already starts with "use client", so you can import it from a Server Component page as usual. With reduced motion enabled, the component switches to its static version only after mounting, so the first render matches the SSR output.
How much page height does scroll mode take?
The wrapper is height multiplied by the number of bands, with a height-tall viewport pinned by sticky; scroll progress maps to each band in turn. Scroll mode needs a numeric height; with a string it falls back to 440 to compute the scroll distance.
Why are the bands cramped or the content cut off?
Collapsed bands are fixed at collapsedSize, and the expanded band gets the remaining space. Make sure height is at least collapsedSize times the number of bands, with enough room left for the expanded content.
How do I change the colours?
Set each band's left accent bar with accentClassName, for example "bg-amber-400 dark:bg-amber-500"; adjust the overall look with className and the per-band stratumClassName.
Does it support keyboards and screen readers?
Yes. Headers are native buttons with aria-expanded; arrow keys move between bands and Home/End jump to the first and last. Collapsed content regions are marked inert so focus can't land in them.
Stage Manager Scenes
A stage-managed layout — the main scene sits center stage while the rest stack as tilted thumbnails in a sidebar, swapping places with shared-element FLIP and a depth-of-field blur when selected.
View Continuity Grid
A real view transition between a card grid and a detail page — the clicked card's image and title carry across with the View Transitions API, the other cards scatter outward by distance and return in sequence on the way back.