Angled Gallery Hero
A hero with the headline on the left and a gallery of images set at a 3D angle drifting slowly sideways on the right, two rows in opposite directions, pausing on hover.
A landing-page hero: an eyebrow, headline, supporting copy and two CTAs on the left, and a gallery tilted with rotateY on the right. Each row of cards loops slowly sideways, neighbouring rows run in opposite directions at slightly different speeds, and both edges fade out with a gradient mask. Hovering or keyboard-focusing the gallery pauses it, and the card under the pointer lifts forward. With no images supplied, it draws warm-gradient placeholders with mountain, sun and window-pane geometry.
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 angled-gallery-hero.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<AngledGalleryHero/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/angled-gallery-hero.en.jsonOr, once registries are configured in components.json, install it as @webberui/angled-gallery-hero.
Usage
import { AngledGalleryHero } from "@/components/ui/angled-gallery-hero";
<AngledGalleryHero
eyebrow="穗光攝影工作室"
title="把每一次快門,排成一面會呼吸的牆"
subtitle="婚禮、商品與街拍作品集中展示。"
primaryAction={{ label: "預約拍攝", href: "/booking" }}
secondaryAction={{ label: "看完整作品", href: "/works" }}
images={[
{ src: "/works/01.jpg", alt: "海邊婚禮" },
{ src: "/works/02.jpg", alt: "手沖咖啡商品照" },
// 6–12 images work well
]}
/>The sample copy reads: eyebrow "Ember Grain Studio", headline "Every shutter click, arranged into a wall that breathes", buttons "Book a shoot" and "See all work".
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Headline (required) |
eyebrow | ReactNode | — | Small label above the headline |
subtitle | ReactNode | — | Supporting copy below the headline |
primaryAction | AngledGalleryHeroAction | — | Primary button, filled with the accent colour |
secondaryAction | AngledGalleryHeroAction | — | Secondary button, outlined |
as | "h1" | "h2" | "h1" | Heading level |
minHeight | number | 560 | Minimum section height (px) |
images | AngledGalleryHeroImage[] | 8 placeholders | Gallery images; items without src draw a placeholder |
angle | number | -18 | Gallery rotateY angle (deg); when omitted, --wb-angled-gallery-hero-angle is used |
rows | 1 | 2 | 3 | 2 | Number of rows; adjacent rows drift in opposite directions |
pauseOnHover | boolean | true | Pause the drift while the pointer is over the gallery |
galleryLabel | string | "作品畫廊" (Work gallery) | Accessible name of the gallery region |
className | string | — | Classes merged into the root section |
AngledGalleryHeroAction
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Button label |
href | string | — | Renders an a link when set, otherwise type="button" |
onClick | () => void | — | Click callback |
AngledGalleryHeroImage
| Field | Type | Default | Description |
|---|---|---|---|
src | string | — | Image URL; omit to draw a placeholder |
alt | string | — | Alt text, also the placeholder's accessible name |
How it works
- The gallery container has
perspective: 1200px; the inner layer isrotateY(var(--wb-angled-gallery-hero-angle, -18deg)) rotateX(6deg). - Each row's content is duplicated, and
translateXruns linearly from 0 to -50% before looping seamlessly. The period is--wb-angled-gallery-hero-duration(default40s); row two runs in reverse at 1.25×, row three forward at 1.5×. - Entrance: eyebrow, headline, copy and CTAs rise 16px and fade in one after another, 80ms apart, over
--wb-angled-gallery-hero-enter-duration(default600ms). - Accent:
--wb-angled-gallery-hero-accent(default#0d9488in light mode,#2dd4bfin dark), used for the eyebrow, primary button and focus ring. - From
mdup it is a 5 / 7 two-column layout; on narrow screens the gallery moves below the headline.
Accessibility
- The root is a
sectionlabelled by the headline viaaria-labelledby; the heading level comes fromas. - The gallery is a
regionwith anaria-labeland can be focused with Tab; focus always pauses the drift (regardless ofpauseOnHover) so keyboard users can stop the moving content. - The duplicate loop copy and the cards in rows after the first are
aria-hidden, so screen readers hear each image's alt text once. - CTAs are
aortype="button"with a clear focus-visible ring. - When the system's reduce motion setting is on, all looping drift stops and a static composition is shown, and the entrance becomes a 150ms fade; a CSS media query applies this from the first paint.
Newsletter Signup Section
A subscription form section with input animation, a submit-success transformation, and social proof.
Contact Bar Hero
A hero with a raised contact bar under the headline — one-click email copy, a phone link and a booking button — which can dock to the bottom of the viewport once the hero scrolls away.