Arrival Hero with Stay Bar

A whitewashed stone hotel stepping down a hillside to a cove at sunset, with a pool and olive trees

Ostria, Paros

Twelveroomsaboveaquietcove.

A small stone house among old olive trees, with the sea at the end of every path and nothing to do until dinner.

Guests2 guests

Booking here is always the best rate, with breakfast on the terrace included.

About this block

Arrival Hero with Stay BarPRO

A full-height hotel hero: the photograph zooms out on load and drifts slower than the page, a serif headline settles in word by word, and a stay bar whose arrival and departure open a two-month range calendar, a guest stepper and a check availability pill submits straight to your booking engine.

Hotel1: Arrival Hero with Stay Bar

A full-height photographic hero whose image zooms out of a blur once it loads and then scrolls slower than the page, with a serif headline that arrives word by word and a stay bar underneath that picks dates on a range calendar, counts guests and sends both to your booking engine.

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://beste.dev/r/hotel1?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

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

This installs the block to components/beste/block/hotel1.tsx plus the button22 sliding-marker pill used for the submit button, the text1 word stagger behind the headline, and the shadcn/ui calendar and popover primitives that hold the arrival and departure picker.

Quick start

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

tsx
import { Hotel1, hotel1Demo } from "@/components/beste/block/hotel1";

export default function Page() {
  return <Hotel1 {...hotel1Demo} />;
}

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

tsx
import { Hotel1 } from "@/components/beste/block/hotel1";

export default function Page() {
  return (
    <Hotel1
      eyebrow="Ostria, Paros"
      heading="Twelve rooms above a quiet cove."
      description="A small stone house among old olive trees, with the sea at the end of every path."
      image={{
        src: "https://oud.pics/b/hotel/ostria-exterior-golden.webp",
        alt: "A whitewashed stone hotel stepping down a hillside to a cove at sunset",
      }}
      form={{
        action: "https://booking.example.com/ostria",
        params: { checkIn: "checkin", checkOut: "checkout", guests: "adults" },
        defaultGuests: 2,
        maxGuests: 6,
        submitLabel: "Check availability",
        labels: { checkIn: "Arrive", checkOut: "Leave", pick: "Add a date", guests: "Guests", fewer: "Fewer guests", more: "More guests" },
        guestUnit: { one: "guest", other: "guests" },
      }}
      note="Booking here is always the best rate, with breakfast included."
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstring–Uppercase line above the heading
headingstring–Serif <h1>, staggered word by word through Text1
descriptionstring–Paragraph under the heading
imageImage–Full-bleed background photograph
formStayForm–Stay bar with dates, guest stepper and submit pill; hidden when omitted
notestring–Small line under the stay bar
classNamestring–Extra classes for the outer <section>
ts
type Image = {
  src: string;
  alt: string;
};

type StayForm = {
  action: string;
  params?: { checkIn?: string; checkOut?: string; guests?: string };
  defaultGuests?: number;
  maxGuests?: number;
  submitLabel: string;
  labels: { checkIn: string; checkOut: string; pick: string; guests: string; fewer: string; more: string };
  guestUnit: { one: string; other: string };
};

Behavior notes

  • The photograph starts at 1.12 scale, blurred and transparent, and settles over 2.4 seconds only after the file has loaded. While the section scrolls out, the image moves down by up to 24% for a parallax drift. With reduced motion, both the zoom and the parallax are skipped.
  • The eyebrow, description, stay bar and note fade up on mount, each delayed by the number of words in the heading so they follow the headline stagger instead of racing it.
  • The two date fields are one button that opens a range calendar in a popover. It shows two months from the medium breakpoint and one below it, disables days before today, and closes itself once a departure after the arrival is picked.
  • The form submits with GET to form.action. Dates go out as local YYYY-MM-DD values in hidden inputs named by params.checkIn and params.checkOut (default checkin and checkout), and the guest count in one named by params.guests (default adults).
  • Submitting without both dates is blocked and opens the calendar instead.
  • The guest stepper runs from 1 to maxGuests (8 when unset), starts at defaultGuests (2 when unset), disables each button at its limit, and announces the count through a polite live region using guestUnit.one or guestUnit.other.
  • The stay bar is a single column on phones and four cells (two dates, guests, submit) from the medium breakpoint.

Wiring the form up

The form posts to the action you pass. To validate on the client and handle submission in React instead, see React Hook Form, TanStack Form, and Formisch.

More Hotel blocks

View all Hotel
PRO

hotel2

Day in Four Hours Hero

PRO

hotel19

Opening Shutters Hero

PRO

hotel22

Widening Horizon Hero

Get Pro