# Golden Hour CTA

> A closing call to action across a full-width Golden Hour scene. The sun sets as the section comes into view and the road's lights come on; describing a trip and sending it brings out the night and the moon.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/golden-hour-cta).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/golden-hour-cta
- Screenshot: https://shadcn.exchange/shot/keyframeui/golden-hour-cta/light.png
- Registry item: https://keyframeui.com/r/golden-hour-cta.json
- Categories: blocks, cta-sections
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/golden-hour-cta.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `motion`
- Registry items: `https://keyframeui.com/r/golden-hour.json`

## Notes from the registry

Live preview and the components it's built with: https://keyframeui.com/blocks/cta-sections/golden-hour-cta

## Files

### `registry/blocks/golden-hour-cta.tsx`

```tsx
"use client";

import * as React from "react";
import { useInView } from "motion/react";

import { GoldenHour } from "@/components/ui/golden-hour";

/* ── Content ─────────────────────────────────────────────────
 * Everything you'd change to make the section yours: the copy,
 * the field's prompt and the hours the scene is lit for on the
 * way in, once it's in view and after the visitor sends it.
 * ─────────────────────────────────────────────────────────── */

const EYEBROW = "Meander";
const HEADLINE = "Your next weekend starts with one sentence.";
const SUBLINE =
  "Say where you'd like to wake up. Meander plans the days around the light and links every stop to where it found it.";
const FIELD_LABEL = "Describe your trip";
const PLACEHOLDER = "A slow weekend by the sea";
const BUTTON = "Plan it";
const NOTE = "Free for your first three trips. No card needed.";
const SENT = "Planning now. Your trip and its sources land in your inbox in about a minute.";

/** Hours of the day (0–24) for the scene: scrolling toward it, once it's in view, and after sending. */
const HOURS = { before: 17.6, inView: 19.1, sent: 21.8 };

/* ── Section ─────────────────────────────────────────────── */

export function GoldenHourCta() {
  const ref = React.useRef<HTMLElement>(null);
  const inView = useInView(ref, { amount: 0.45 });
  const [trip, setTrip] = React.useState("");
  const [sent, setSent] = React.useState(false);
  const hour = sent ? HOURS.sent : inView ? HOURS.inView : HOURS.before;

  return (
    <section ref={ref} aria-labelledby="golden-hour-cta-title" className="bg-zinc-950">
      <GoldenHour
        time={hour}
        horizon={0.64}
        className="flex min-h-[38rem] flex-col items-center px-6 pt-20 pb-64 text-center text-white sm:min-h-[44rem] sm:pt-28"
      >
        <p className="flex items-center gap-2 text-sm font-medium text-white/80">
          <MeanderMark className="size-4" />
          {EYEBROW}
        </p>
        <h2
          id="golden-hour-cta-title"
          className="mt-5 max-w-[18ch] text-4xl/[1.04] font-medium tracking-[-0.035em] text-balance sm:text-6xl/[1]"
        >
          {HEADLINE}
        </h2>
        <p className="mt-5 max-w-lg text-base/7 text-pretty text-white/80 sm:text-lg/8">{SUBLINE}</p>

        <div className="mt-9 w-full max-w-xl" aria-live="polite">
          {sent ? (
            <p className="flex min-h-14 items-center justify-center gap-2 rounded-full bg-zinc-950/25 px-6 py-3 text-sm font-medium ring-1 ring-white/25 backdrop-blur-xl">
              <CheckIcon className="size-4 shrink-0" />
              {SENT}
            </p>
          ) : (
            <form
              onSubmit={(event) => {
                event.preventDefault();
                if (trip.trim()) setSent(true);
              }}
              className="flex h-14 items-center gap-2 rounded-full bg-zinc-950/25 p-1.5 ring-1 ring-white/25 backdrop-blur-xl transition-shadow duration-200 focus-within:ring-white/70"
            >
              <label htmlFor="golden-hour-cta-trip" className="sr-only">
                {FIELD_LABEL}
              </label>
              <input
                id="golden-hour-cta-trip"
                value={trip}
                onChange={(event) => setTrip(event.target.value)}
                placeholder={PLACEHOLDER}
                autoComplete="off"
                className="h-full min-w-0 flex-1 bg-transparent pl-5 text-[15px] text-white outline-none placeholder:text-white/70"
              />
              <button
                type="submit"
                className="h-full shrink-0 rounded-full bg-white px-6 text-sm font-medium text-zinc-950 transition-[background-color,scale] duration-150 ease-out hover:bg-white/90 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white active:scale-[0.97]"
              >
                {BUTTON}
              </button>
            </form>
          )}
        </div>
        <p className="mt-4 text-sm text-white/70">{NOTE}</p>
      </GoldenHour>
    </section>
  );
}

/* ── Icons ───────────────────────────────────────────────── */

function MeanderMark({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 16 16" className={className} fill="none" stroke="currentColor" strokeWidth={1.6} aria-hidden>
      <path d="M3 14c0-3 4-3 4-6S4 5 6 2.5M9.5 14c0-2.5 3.5-2.5 3.5-5" strokeLinecap="round" />
    </svg>
  );
}

function CheckIcon({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 16 16" className={className} fill="none" stroke="currentColor" strokeWidth={1.8} aria-hidden>
      <path d="m3.5 8.5 3 3 6-7" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}
```
