Photo Callout Markers

(Read the picture)

Four decisions you can see from the doorway.

Every mark on the photograph is a choice we had to defend. Select one to read why it survived.

Signage system mounted across a minimal lobby wall
About this block

Photo Callout MarkersPRO

Wide photograph carrying numbered markers placed by percentage coordinates, paired with a ruled four-column list where the selected entry repeats the marker as a filled seal, darkens its rule and brings its text forward.

Feature247: Photo Callout Markers

An annotated photograph: numbered markers sit on the image at coordinates you supply, and a ruled index underneath explains each one. Selecting either the marker or its entry moves the whole section to that callout.

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

Base UI flavor

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

This installs the block to components/beste/block/feature247.tsx plus the badge7 eyebrow it uses.

Quick start

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

tsx
import { Feature247, feature247Demo } from "@/components/beste/block/feature247";

export default function Page() {
  return <Feature247 {...feature247Demo} />;
}

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

tsx
import { Feature247 } from "@/components/beste/block/feature247";

export default function Page() {
  return (
    <Feature247
      badge={{ label: "Read the picture" }}
      heading="Four decisions you can see from the doorway."
      description="Every mark on the photograph is a choice we had to defend."
      image={{ src: "/work/lobby.jpg", alt: "Signage across a lobby wall" }}
      callouts={[
        {
          index: "1",
          title: "Type at reading height",
          description: "Set at 44 millimetres so it lands at eye level for a standing adult.",
          x: 22,
          y: 32,
        },
        {
          index: "2",
          title: "One rule, never two",
          description: "A single hairline separates the directory from the wall.",
          x: 48,
          y: 58,
        },
      ]}
    />
  );
}

Props

PropTypeDefaultDescription
badge{ label: string }Eyebrow label rendered as a Badge7
headingstringSection heading in the left header column
descriptionstringSupporting paragraph in the right header column
image{ src: string; alt: string }The photograph the markers are placed on
calloutsCallout[][]Markers and their explanations, in reading order
classNamestringExtra classes for the outer <section>
ts
type Callout = {
  index: string;
  title: string;
  description: string;
  /** Horizontal position of the marker, as a percentage of the image width */
  x: number;
  /** Vertical position of the marker, as a percentage of the image height */
  y: number;
};

Behavior notes

  • x and y are percentages of the image box, applied as inline left and top with a -translate-x-1/2 -translate-y-1/2 offset, so a marker stays on the same part of the picture at every screen width.
  • The first callout is selected on mount (useState(0)), which means the section never opens in a blank state.
  • Selection is expressed three ways at once: the marker on the photograph turns into a light seal with a ring-4 halo, the index entry's seal inverts to bg-foreground text-background, and its top rule darkens from border-border to border-foreground. Color alone is never the signal.
  • Unselected index entries fade their description to text-muted-foreground/60 rather than hiding it, so the whole list stays readable and scannable.
  • Both the marker and the index entry are real button elements with aria-pressed and, on the markers, an aria-label carrying the callout title, so the state is exposed to assistive technology.
  • The image switches ratio rather than height: aspect-[16/10] on mobile becomes md:aspect-[2/1], which keeps marker coordinates meaningful without letterboxing a phone.
  • The index is a four-column grid on md, so a set of four callouts lines up with the markers left to right.

More Feature blocks

View all Feature
PRO

feature287

Photo Steps

Three numbered steps in columns, each topped by a photograph that drifts inside its frame, with a serif title and a description, under a serif heading that settles in word by word and a sliding-marker pill.

PRO

feature279

Photo Band Feature

A feature that opens on a rounded photographic band with a dark scrim and film grain, the photograph drifting as the page scrolls under a serif heading that settles in word by word and a light sliding-marker pill, then three ruled points beneath it.

PRO

feature253

Wide Band With Field Facts

Cinematic image band carrying a pill label in its corner, followed by a ruled four-column row where each measured fact pairs an oversized figure with a sentence of testing context, with the outline pill CTA sitting on the heading line.

PRO

feature250

Sticky Photo With Notes

A single tall photograph pinned with position sticky, captioned without a rule, while a column of eyebrow-led notes scrolls past it, each note after the first opening on its own hairline.

PRO

feature227

Sticky feature list with images

Sticky left intro paired with a stacked, numbered list of feature blocks, each with a title, description, and small image.

PRO

feature233

Compact two-column icon feature list

A header with a badge, heading, and description, followed by many compact items in a two-column grid — each a lucide icon in a rounded bg-muted tile beside a title and one-line description.