Aurora Glass Testimonials — Interactive 3D Card Stack
An interactive 3D stack of glass testimonial cards: single-file HTML, Tailwind CSS and vanilla JS.
by UpForkComponentUpdated 4 Oct 2026
Code
1 file · 12 assets
Free for members
Sign up (it's free) to read the files above, copy them, install them with one command or download them as a ZIP.
Sign up freeAbout
A premium testimonials section: a 3D stack of glassmorphic review cards over a slowly drifting aurora. Drag or swipe the front card to send it to the back, use the buttons or the arrow keys, or let it play on its own. It is fully accessible, works without JavaScript, has light and dark themes, and is a single HTML file with no framework and no build step.
- The stack: the front card is flat and sharp. The cards behind it are smaller, higher, farther away, slightly rotated, and they fade and soften with depth. Click one to bring it forward.
- The glass: backdrop blur with saturation, a 1px gradient border (bright top-left, fading bottom-right), an inner top highlight, two-layer shadows, a fine grain, and a specular sheen that follows the cursor.
- The motion: swipe with mouse or touch, and the card flies to the side, then behind the stack. The front card tilts toward the cursor, and its quote mark and avatar move a little more (parallax). Autoplay shows a progress line and pauses on hover, focus, drag, a hidden tab or the pause button. When the section scrolls into view, the header rises, the cards fan in one by one, the stars fill and the numbers count up.
- The trust bar: stacked avatars, the aggregate rating and review count, and monochrome client logos.
- Accessibility: a labelled carousel region with slides as
<figure>/<blockquote>/<figcaption>, a polite live region, labelled buttons, visible focus, and ratings read as "Rated 5 out of 5". Reduced motion turns off autoplay, tilt and drift. Without JavaScript the cards are a plain responsive grid. - SEO: JSON-LD (
ProductwithAggregateRatingand eachReview) generated from the same data. - Themes: light and dark from
prefers-color-scheme, overridable withdata-theme. Every color, radius, blur and timing is a CSS custom property. - Reusable: any number of instances on one page, with no global ids needed.
Run the demo
Open index.html in a browser. That's it: the demo needs no server and no build.
The demo page has a light / system / dark switch in the top right corner and a second instance further down (forced dark, a rose accent, no autoplay, cards rendered from JSON).
Files
index.html the demo: everything inlined (generated from src/ by npm run build)
avatars/ demo avatars (credits in PHOTOS.md)
fonts/ Geist, Latin subset (SIL OFL 1.1, fonts/OFL.txt)
src/agt.css the component's styles: tokens, glass, stack, aurora, motion
src/agt.js the component's script
src/testimonials.json the demo reviews
src/page.html the demo page template
src/tailwind.css Tailwind entry for the section layout and demo page
scripts/build.mjs builds index.html
Use it on your site
-
Markup: copy the
<section class="agt" data-agt …>block fromindex.html. It holds the aurora, header, stage, controls, trust bar and the reviews as JSON. -
Styles: copy the component's
<style>block (the one after the Tailwind block). It is plain CSS and works with or without Tailwind. The section's layout (header, controls row, trust bar) uses a few Tailwind utilities: on a Tailwind site they are generated for you, and anywhere else, copy the Tailwind<style>block too, or restyle those wrappers. -
Script: copy the component's
<script>block, or save it asagt.jsand load it at the end of the page. -
Add
agt-jsto<html>as early as possible (the demo does it in<head>) so the stack, not the no-JS grid, shows from the first paint:<script>document.documentElement.classList.add("agt-js")</script>
Every [data-agt] section on the page mounts itself. For a section added later:
AuroraGlassTestimonials.mount(element, { interval: 8000 });
Data
The reviews live in one JSON block inside the section:
<script type="application/json" data-agt-data>
{
"product": "Your product",
"aggregate": { "rating": 4.9, "count": 1240 },
"reviews": [
{
"id": "maya-okafor",
"quote": "We replaced three tools with one…",
"name": "Maya Okafor",
"role": "Head of Product",
"company": "Fieldnote",
"avatar": "avatars/maya-okafor.jpg",
"rating": 5,
"verified": true,
"source": "Customer survey",
"date": "2026-09-14"
}
]
}
</script>
- Leave the stage empty: the script renders the cards (and their JSON-LD) from this JSON.
- Run
npm run buildafter editingsrc/testimonials.json: the cards are pre-rendered into the HTML, so they work without JavaScript and search engines read them without running scripts. - Avatars:
avataris optional. Without it, or if the image fails to load, the initials show instead. Keep quotes to about three lines.
Options
Set them in data-agt-config on the section (JSON), in a "config" object in the data, or as the second
argument to mount():
| Option | Default | What it does |
|---|---|---|
autoplay | true | Advance on its own, with a progress line on the front card. |
interval | 6000 | Milliseconds per card. |
loop | true | false stops at the first and last card. |
tilt | true | Tilt and parallax toward the cursor (mouse only). |
maxVisible | 4 | Cards visible in the stack. Phones show 2: the front card and a peek of the next. |
theme | "auto" | "light" or "dark" fixes the section's theme. |
schema | true | Add JSON-LD when the cards are rendered from JSON. |
<section class="agt" data-agt data-agt-config='{"autoplay": false, "maxVisible": 3}'>
API and events
Each section element gets next(), prev(), goTo(index), pause() and play(), and fires agt:change:
const section = document.querySelector("[data-agt]");
section.addEventListener("agt:change", (event) => console.log("now showing", event.detail.index));
section.goTo(2);
Keyboard, with the stage focused: ← / → move, Home / End jump to the first or last card.
Theming
Override any --agt-* property on the section, in your CSS or inline:
.agt {
--agt-accent: #f97316;
--agt-radius: 20px;
--agt-blur: 18px;
--agt-interval: 8000ms;
}
Colors are written with light-dark(), so one declaration covers both themes: --agt-accent: light-dark(#c2410c, #fb923c). The main tokens are --agt-accent, --agt-accent-2, --agt-blob-1/2/3 (the
aurora), --agt-bg, --agt-text, --agt-text-2, --agt-text-3, --agt-glass-bg, --agt-edge-1/2/3 (the
gradient border), --agt-radius, --agt-blur, --agt-card-w, --agt-card-h, --agt-lift, --agt-depth and
--agt-shrink.
The theme follows the visitor's setting. data-theme="light" or "dark" on the section, or on any ancestor
such as <html>, overrides it.
Accessibility
<section aria-labelledby>(the script names the section after its heading when you don't), a stage withrole="region"andaria-roledescription="carousel", and slides asrole="group"witharia-label="Testimonial 2 of 6". Cards behind the front one arearia-hidden.- Changes are announced in a polite live region, but not while autoplay is running, following the WAI carousel pattern. The pause button stops autoplay for good; hover and focus pause it too.
- Real buttons with labels, keyboard control, and focus rings in both themes.
- Text on the glass is 4.5:1 or better in both themes. Where
backdrop-filteris unsupported, the cards turn more opaque. - With
prefers-reduced-motion: reducethere is no autoplay, tilt, drift or flight, and changes are simple fades.
Performance
Only transform, opacity and (on a few elements) filter animate. Pointer effects are eased in
requestAnimationFrame and written as CSS variables. Avatars load lazily and decode asynchronously. The stage
reserves its height, so nothing shifts. The script is about 8.8 KB minified (3.7 KB gzipped), including the
optional JSON renderer and JSON-LD generator; the CSS for the component is about 20 KB unminified.
Rebuilding
pnpm install
pnpm build
The build compiles the Tailwind utilities the page uses, pre-renders the cards and the JSON-LD from
src/testimonials.json with the component's own template, and inlines everything into index.html.
Browser support
The latest Chrome, Edge, Safari, Firefox and iOS Safari (CSS light-dark() needs Safari 17.5 or newer).
-webkit-backdrop-filter and -webkit-mask are included.
Before you publish
The demo reviews, names, companies and numbers are placeholders. Replace them with real reviews, from people
who agreed to be quoted. Search engines treat review markup (the JSON-LD) for invented reviews as spam: set
"schema": false until the reviews are real.
Before you buy
Everything you need to know
How this component gets from the preview into your project, and what buyers ask most.
How to use it
From the preview to your project
- 01
Try it in the preview
Switch between light and dark, and resize it to phone and tablet widths, before you decide.
- 02
Get it
Free products are yours with a free account. Paid ones settle in USDT on TRON, sent straight to the wallet on your order.
- 03
Install it
Components go into your project with one shadcn command, dependencies included. Everything else downloads with a checksum.
- 04
Make it yours
It's your code now: rename it, restyle it and wire in your real data.
- 05
Or hand it to your AI
Copy the prompt and let your coding assistant place it in your project, following your conventions.
Yes, a free one: it keeps your order, every payment you make for it and the files together. Free products need it too: without an account you can look and try the live preview, but not download, install or copy anything.
Send the price as a USDT transfer on TRON (TRC-20) to the wallet on your order, shown with its QR code, then paste the transaction ID on the order. It's checked on-chain, and the files unlock once it's confirmed. Paid less? You're asked for the rest.
Yes. The Standard License covers unlimited personal and commercial projects, client work included; just don't resell it on its own. Open-source licenses say so on the product.
Create a CLI token on your account page, put it in your project's .env.local, add UpFork to components.json once, and install with npx shadcn add: free and paid components alike.
Onto your order, in your account. Download links last ten minutes and can be made again.
Releases are scanned for malware and reviewed before anyone can download them, and every file shows its SHA-256 so you can check what you got.
Building with an AI assistant?
Copy a ready-made prompt with the code, its dependencies and a demo, and your assistant can put it in place for you.
Selling your own work?
Get approved once, then publish components, templates and apps, paid in USDT straight to your own wallet.
Components



