Page Sections

Flip Portrait Tiles

A wall of square portrait tiles that flip over in 3D on hover or tap to reveal the quote on the back, with touch and keyboard support.

Show customer testimonials as a wall of square portrait tiles. The front is a gradient portrait placeholder generated from a hue (or your own photoSrc) with the name and title overlaid in the bottom-left corner; when the pointer enters, the tile flips over in 3D on a spring and the back shows the quote, company and star rating. The flip direction follows the edge the pointer entered from; on touch devices a tap flips the tile and another tap flips it back, and keyboard users toggle with Enter or Space. On entrance the tiles fade in staggered along the diagonal.

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 flip-portrait-tiles.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

220
Active edited usageDefault props
<FlipPortraitTiles/>

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/flip-portrait-tiles.en.json

Or, once registries are configured in components.json, install it as @webberui/flip-portrait-tiles.

Usage

import { FlipPortraitTiles } from "@/components/ui/flip-portrait-tiles";

<FlipPortraitTiles
  eyebrow="客戶回饋"
  title="他們這樣說"
  columns={4}
  testimonials={[
    {
      quote: "改版後的訂位頁讓週末候位少了一半。",
      highlight: "少了一半",
      name: "林曉晴",
      role: "店長",
      company: "青嶼咖啡",
      rating: 5,
    },
    {
      quote: "司機端的簽收流程終於順了。",
      name: "陳柏宇",
      role: "營運主管",
      company: "北辰物流",
      rating: 4,
      photoSrc: "/images/chen.jpg",
    },
  ]}
/>

Props

PropTypeDefaultDescription
testimonialsFlipPortraitTilesItem[]—Testimonials to show (required)
eyebrowstring—Small label above the title
titlestring"客戶怎麼說" ("What our customers say")Section title, also the section's accessible name
subtitlestring—Supporting text below the title
columns3 | 44Column count at desktop width; drops to 2–3 columns on narrow screens
trigger"hover" | "click" | "auto""auto"Trigger; auto uses hover for fine pointers (mouse) and tap for touch
flipDirection"auto" | "horizontal" | "vertical""auto"Flip direction; auto follows the edge the pointer entered from
stiffnessnumber—Flip spring stiffness; reads --wb-flip-portrait-tiles-stiffness when omitted, then falls back to 220
valuenumber[]—Controlled: indices of the flipped tiles
defaultValuenumber[][]Initially flipped indices in uncontrolled mode
onChange(value: number[]) => void—Fires when the flipped set changes, with the flipped indices in ascending order
classNamestring—Merged into the root section

FlipPortraitTilesItem

FieldTypeDefaultDescription
quotestring—Quote text; shrinks to small type past 120 characters
namestring—Name
rolestring—Job title
companystring—Company name, shown at the bottom of the back face
ratingnumber—Star rating (0–5), rounded for display
avatarHuenumberDerived from indexHue (0–360) of the portrait placeholder; assigned by index with the 137.508° golden angle by default
highlightstring—Fragment of the quote to mark in the accent color
metric{ value: string; label: string }—Result metric shown at the top of the back face
photoSrcstring—Portrait photo URL; replaces the gradient silhouette

How it works

  • Flip direction: with flipDirection="auto" the edge nearest to where the pointer entered decides — enter from the left and it flips right, from the right it flips left, from the top it flips down, from the bottom it flips up; on touch the edge nearest to the press point decides. A flipped tile never changes axis, so it cannot jump mid-flip.
  • Trigger: auto checks (pointer: coarse). SSR and the first render always use hover mode and switch after mount. In hover mode several tiles can be open at once; in tap mode each tile toggles on its own and a second tap flips it back.
  • Timing and color: spring damping is fixed at 22, stiffness comes from stiffness or --wb-flip-portrait-tiles-stiffness; the accent only flows through --wb-flip-portrait-tiles-accent (default #0d9488, #2dd4bf in dark mode) and is used for highlights, stars and the focus ring.
  • The portrait placeholder needs no image: a two-tone gradient from the hue plus an abstract bust silhouette. The hue is deterministic, so server and browser render the same thing.

Accessibility

  • The root is a section labelled by its title via aria-labelledby
  • Each tile's interaction layer is a button with aria-pressed (flipped or not) and an aria-label of "查看 name 的評價" ("View name's testimonial" in the English build); Tab moves between tiles, Enter or Space flips
  • The quote is rendered as figure / blockquote / figcaption outside the button: the back face is aria-hidden while unflipped and readable once flipped; the stars carry hidden "Rated N out of 5" text
  • When the user has reduce motion enabled, there is no 3D rotation or scale entrance — flipping becomes a 150ms crossfade between front and back, and the entrance is a plain fade