Voices Rail

Hotel Maren, twelve rooms above the bay

What our guests take home.

No stars on the door and no spa menu. Just what people wrote to us after they left.

We came for three nights and changed our flights twice.

Portrait of Chet Baker

Chet Baker

Stayed in May

The room had nothing in it that did not need to be there, and somehow that was the most generous thing about it.

Portrait of Ella Fitzgerald

Ella Fitzgerald

Architect, Lisbon

Quiet timber-clad guest room

Breakfast on the terrace ruined every other breakfast for me.

Portrait of Thelonious Monk

Thelonious Monk

Stayed in September

They remembered how I take my coffee on the second morning and never once asked me to rate anything. I will be back every year.

Portrait of Joni Mitchell

Joni Mitchell

Writer, Montreal

Light-filled lounge with low furniture

The quietest week I have had in ten years.

Portrait of Stevie Wonder

Stevie Wonder

Stayed in October

We asked where to swim and the owner walked us down to a cove that is not on any map. That is the review.

Portrait of Aretha Franklin

Aretha Franklin

Stayed in June

Rated 4.9 out of 5 by 1,240 guests since we opened in 2016.

About this block

Voices RailPRO

A pinned scroll testimonial section for a small hotel built on the scroll-rail component, set on a warm muted surface: the heading and intro open a rail of guest quotes that travels sideways as the page scrolls. Each quote is a large serif pull quote with a faint oversized quotation mark drifting behind it and a byline with a round portrait, name and role, and quotes brighten as they reach the middle. Short and long quotes alternate in width, and a tall photograph that moves slower than its frame sits after every second quote. A rating summary with an Arrow Pill ends the rail. Reduced motion turns the rail into a plain horizontal scroll.

Feature317: Voices Rail

A pinned scroll testimonial section on a muted surface built on the scroll-rail component: the heading and intro open a rail of large serif pull quotes that travels sideways as the page scrolls, with tall photographs set between the quotes and a rating summary with an Arrow Pill at the end.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/feature317?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/feature317?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/feature317.tsx plus the scroll-rail component and the button23 button it uses.

Quick start

The installed file exports feature317Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.

tsx
import { Feature317, feature317Demo } from "@/components/beste/block/feature317";

export default function Page() {
  return <Feature317 {...feature317Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { Feature317 } from "@/components/beste/block/feature317";

export default function Page() {
  return (
    <Feature317
      eyebrow="Hotel Maren, twelve rooms above the bay"
      heading="What our guests take home."
      description="No stars on the door and no spa menu. Just what people wrote to us after they left."
      voices={[
        {
          quote: "We came for three nights and changed our flights twice.",
          name: "Chet Baker",
          role: "Stayed in May",
          avatar: { src: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=160&h=160&fit=crop&q=80", alt: "Portrait of Chet Baker" },
          size: "large",
        },
        {
          quote: "The room had nothing in it that did not need to be there, and somehow that was the most generous thing about it.",
          name: "Ella Fitzgerald",
          role: "Architect, Lisbon",
          avatar: { src: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=160&h=160&fit=crop&q=80", alt: "Portrait of Ella Fitzgerald" },
          size: "medium",
        },
      ]}
      photos={[{ src: "https://images.unsplash.com/photo-1777523743687-233bbfdbd894?w=1200&q=80", alt: "Quiet timber-clad guest room" }]}
      summary="Rated 4.9 out of 5 by 1,240 guests since we opened in 2016."
      button={{ label: "Read all reviews", href: "/reviews" }}
      rail={{ gap: 112, align: "center", smoothing: 0.5 }}
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstring–Small line above the heading
headingstring–Section heading, rendered as an h2
descriptionstring–Intro under the heading
voicesVoice[][]The quotes along the rail, in order
photos{ src: string; alt: string }[][]Tall photographs, one placed after every second quote
summarystring–Closing line in the last panel
buttonActionButton–Dark Arrow Pill under the summary
railOmit<ScrollRailProps, "children" | "progress" | "autoplay" | "className">–Forwarded to the ScrollRail component: gap, align, speed, smoothing and paused
classNamestring–Extra classes for the outer <section>
ts
type ActionButton = {
  label: string;
  href: string;
};

type Voice = {
  quote: string;
  name: string;
  role: string;
  avatar: { src: string; alt: string };
  size?: "large" | "medium"; // anything but "medium" renders large
};

type Photo = {
  src: string;
  alt: string;
};

Behavior notes

  • The section is 340svh tall with a sticky stage of 100svh - 78px (at least 640px); scroll progress from 0.02 to 0.96 drives the rail with autoplay off.
  • Large quotes are md:w-[34rem] at text-5xl, medium ones md:w-[44rem] at text-4xl, so short and long quotes alternate in width.
  • Photos go in order after the 2nd, 4th and 6th quote and so on; once photos runs out, no more are inserted. Each photo sits in a wider inner layer that drifts slower than its frame (data-rail-depth="0.22").
  • An oversized faint quotation mark drifts behind every quote, and each quote, byline and the summary panel stay dimmed until they reach the middle (data-rail-focus).
  • The summary panel only renders when summary or button is set.
  • With reduced motion the section is not pinned and the rail becomes a plain horizontal scroll.

More Feature blocks

View all Feature
PRO

feature318

Collection Rail

PRO

feature312

Chapters Rail

PRO

feature314

Selected Work Rail

Get Pro access