River Strip

The walk

Fridaysalongtheriver,insixframes.

About this block

River StripPRO

A horizontal, snap-scrolling strip of photographs that starts in line with the heading and runs off the right edge, each frame carrying a serif subject and a small-caps place and month; steered by round arrow buttons, and any frame opens a filmstrip lightbox on ink with film grain, a counter, arrow and keyboard navigation and a thumbnail rail along the foot.

Gallery27: River Strip

A horizontal filmstrip that starts flush with the heading and runs off the right edge, with arrow controls, snap scrolling, and a full-screen lightbox carrying its own thumbnails, counter and keyboard controls.

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/gallery27?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

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

This installs the block to components/beste/block/gallery27.tsx plus the button22 sliding-marker pill and the text1 word stagger it uses.

Quick start

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

tsx
import { Gallery27, gallery27Demo } from "@/components/beste/block/gallery27";

export default function Page() {
  return <Gallery27 {...gallery27Demo} />;
}

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

tsx
import { Gallery27 } from "@/components/beste/block/gallery27";

export default function Page() {
  return (
    <Gallery27
      eyebrow="The walk"
      heading="Fridays along the river, in six frames."
      button={{ label: "Join a walking session", href: "/walking", tone: "outline" }}
      frames={[
        {
          src: "/photos/mist.jpg",
          alt: "Morning mist lifting off a still lake",
          subject: "Mist on the water",
          where: "Tagus estuary, March",
        },
      ]}
      labels={{ previous: "Previous frame", next: "Next frame", close: "Close", open: "Open frame" }}
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstringSmall-caps line above the heading
headingstringSection heading, rendered as an h2 through Text1
buttonActionButtonPill action beside the arrows, hidden below md
framesFrame[][]The photographs, in the order given
labelsGallery27Labels{}Accessible names for the controls
classNamestringExtra classes for the outer <section>
ts
type Frame = {
  src: string;
  alt: string;
  subject: string;
  where: string;
};

type Gallery27Labels = {
  previous?: string;
  next?: string;
  close?: string;
  open?: string;
};

type ActionButton = {
  label: string;
  href: string;
  tone?: "primary" | "light" | "dark" | "outline";
};

Behavior notes

  • The strip's left inset is measured from the header's own bounding box on mount and on resize, so the first frame starts exactly where the heading starts at any width while the strip itself still runs full bleed off the right edge. A padding value guessed from the container would drift as soon as the gutter changed.
  • scrollPaddingLeft is set to the same measurement, so a snapped frame lands on that line rather than against the viewport edge.
  • Arrows scroll by 70% of the visible width rather than by one card, which keeps a partial frame on screen as a hint that the strip continues; the scroll respects reduced motion by falling back to behavior: "auto".
  • The lightbox is a real dialog: role="dialog" with aria-modal, Escape to close, arrow keys to step, and document.body.style.overflow locked while it is open and restored on unmount.
  • Stepping wraps with (value + direction + frames.length) % frames.length, so the arrows cycle rather than dead-ending at either end.
  • Clicking the backdrop closes it, and the image area, caption and thumbnails each call stopPropagation, so clicking a thumbnail changes the frame instead of dismissing the whole thing.
  • Thumbnails carry aria-pressed and an empty alt, since the full-size image beside them already carries the description; the counter is set in tabular-nums so it does not jitter while stepping.
  • Frames enter with a right-edge viewport margin (0px -10% 0px 0px), which is the horizontal equivalent of the vertical margins used elsewhere in the set.

More Gallery blocks

View all Gallery
PRO

gallery4

Wide Slide Reel

Single-frame image reel that slides on a transform, driven by round arrow buttons in the header and a row of bar indicators beside the caption, with no hover behaviour on the image itself.

PRO

gallery11

Full Bleed Strip With Sheet Viewer

Edge-to-edge strip of tall frames opening a viewer where the picture fills the screen and the caption, note and thumbnails sit in a sheet that slides off the bottom when you want the frame uncovered.

PRO

gallery5

Filmstrip Stage Viewer

Cinematic stage frame with the caption and frame counter set on a gradient at its foot, round arrow controls on the picture itself, and a scrolling filmstrip below where the inactive thumbnails sit back at low opacity.

PRO

gallery29

Plate Grid Lightbox

An even three-column grid of photographic plates that open into an ink lightbox: every frame keeps the same ratio so the captions line up, arrows and keys turn the page, either half of the plate is clickable, and a plate that belongs to a page offers it as a link.

PRO

gallery8

Photo Book Spread Viewer

Photographs presented as printed spreads on a soft panel: two plates share a page with a centre rule, round controls turn to the next spread, and a bar index below tracks how far through the book you are.

PRO

gallery26

Cover Archive With Lightbox

A square cover grid that names each picture only on hover and opens it full screen on click, where arrows and the keyboard walk the archive and a link leads into the issue itself.