Date & Time Picker

Live availability

Book your next session

Pick a date and time that works for you. Bookings are confirmed instantly and a reminder is sent 24 hours before.

Deep Tissue Massage
60 min

September 2026

MonTueWedThuFriSatSun
Selected Today Unavailable

Select a date

Pick a date from the calendar to see available time slots.

No date & time selected
About this block

Date & Time PickerPRO

Split-panel booking interface with interactive monthly calendar on the left and time slot grid on the right. Features today highlight, disabled dates, selected state, morning/afternoon grouping, and booking summary footer.

Booking1: Date & Time Picker

A two-panel booking widget rendering an interactive monthly calendar on the left (with prev/next month navigation, today ring, past and unavailable dates struck through and disabled, and a selected-date fill) and a time-slot grid on the right split into morning/afternoon groups, above a sticky footer that summarizes the current date-plus-time pick and a confirm button that stays disabled until both are chosen.

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

Base UI flavor

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

This installs the block to components/beste/block/booking1.tsx, plus the badge and button shadcn/ui primitives it uses for the eyebrow/duration badges and the confirm button.

Quick start

The installed file exports booking1Demo alongside the block: the exact props behind the preview above. Spread it to get a working date-and-time picker in one line.

tsx
import { Booking1, booking1Demo } from "@/components/beste/block/booking1";

export default function BookingPage() {
  return <Booking1 {...booking1Demo} />;
}

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

tsx
import { Booking1 } from "@/components/beste/block/booking1";

export default function BookingPage() {
  return (
    <Booking1
      badge={{ label: "Live availability", variant: "secondary" }}
      heading="Book your <strong>next session</strong>"
      description="Pick a date and time that works for you."
      serviceName="Deep Tissue Massage"
      duration="60 min"
      unavailableDates={["2026-04-14", "2026-04-19"]}
      timeSlots={["09:00", "09:30", "10:00", "13:00", "14:30", "16:00"]}
      unavailableSlots={{ "2026-04-15": ["09:00", "13:00"] }}
      labels={{
        morning: "Morning",
        afternoon: "Afternoon",
        emptyHeading: "Select a date",
        summaryEmpty: "No date & time selected",
        summaryConnector: "at",
        confirmButton: "Confirm Booking",
        days: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
        months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
      }}
    />
  );
}

Props

PropTypeDefaultDescription
badge{ label: string; variant?: "default" | "secondary" | "outline" }Centered eyebrow badge above the heading
headingstringSection heading, supports inline <strong>
descriptionstringMuted paragraph under the heading
serviceNamestringService name shown in the card header with a calendar icon
durationstringDuration text rendered as a secondary badge with a clock icon
unavailableDatesstring[][]ISO date keys (YYYY-MM-DD) that render disabled and struck through
timeSlotsstring[][]All HH:MM slots, auto-split into morning/afternoon at hour 12
unavailableSlotsRecord<string, string[]>{}Map of date key to blocked HH:MM slots for that day
labelsBooking1Labels{}All UI strings, day/month arrays, and legend text
classNamestringExtra classes for the outer <section>
ts
type Booking1Labels = {
  morning?: string;
  afternoon?: string;
  emptyHeading?: string;
  emptyDescription?: string;
  summaryEmpty?: string;
  summaryConnector?: string;
  confirmButton?: string;
  legendSelected?: string;
  legendToday?: string;
  legendUnavailable?: string;
  days?: string[];
  months?: string[];
};

Behavior notes

  • The calendar is hand-built, not the shadcn Calendar component: month/year, selected day, and selected time all live in internal useState seeded from new Date(), and none of them are ever lifted out or exposed via a callback, so the picked date and time are unreachable by the parent.
  • The confirm Button is disabled until both a day and a time are selected, and it carries no onClick, so wiring the actual submit (reading the selection out of the component) is left to the integrator.
  • Dates are matched by ISO string key (toDateKey produces YYYY-MM-DD); a day cell is disabled when it is in the past (isPast) or listed in unavailableDates, and disabled cells render line-through and are unclickable.
  • Time slots are partitioned purely by the hour before the colon: parseInt(time.split(":")[0]) "< 12" goes to the morning group, everything else to the afternoon group, so a malformed slot string falls back to hour 0 (morning).
  • unavailableSlots is keyed by the same date-key format; only the entry for the currently selected day is consulted (via blockedSlots), and blocked slots render disabled and struck through within their group.
  • Changing month via the prev/next chevrons, or picking a new day, resets selectedTime (and month changes also reset selectedDay) to null, clearing the right panel back to its empty state.
  • heading supports inline <strong> markup rendered through dangerouslySetInnerHTML, with <strong> styled bold and in the primary color.
  • Header (serviceName/duration), badge/heading block, legend items, and each label are conditionally rendered, so any omitted string simply drops out; the right panel shows the emptyHeading/emptyDescription placeholder until a date is chosen.

More Booking blocks

View all Booking
PRO

booking24

Service And Slot Picker

An interactive appointment picker: a hairline panel pairing a selectable service list with a scrollable day strip and a time slot grid that marks unavailable times, beside a full-height provider photo with a gradient name card, closing on a live summary bar and confirm action.

PRO

booking18

Cinema Seat Picker

Interactive seat selection grid for cinemas, theaters, and events. Row/column layout with an aisle gap, tier-based pricing (standard/premium/VIP), occupied seats, a live selection summary, and a legend. Includes screen indicator at the top.

PRO

booking6

Restaurant Reservation

Restaurant table reservation with guest count selector, date/time picker, seating preference (indoor/outdoor/bar), special requests textarea, and booking summary. Fine dining reservation flow.

PRO

booking33

Session Picker

A booking chooser: a serif heading that settles in word by word and an intro, then a ruled list of session types on the left that swaps, with a soft blur, the muted detail card on the right showing a serif title, a description, a fact row and a sliding-marker pill.

FREE

booking5

Provider Picker

Staff/provider selection cards with avatar, name, specialty, star rating, review count, availability badge, experience years, and selected state. Grid layout with "Any Provider" option.

FREE

booking4

Service Selector

Service selection grid with category filter tabs, service cards showing icon, name, description, duration, price, and selected state. Ideal for spa, salon, clinic, and fitness booking flows.