# Link booking

A React block (a whole screen) in [Beamline](https://beamline.io/)'s [HR & payroll](https://beamline.io/components/apps/hr-payroll) app. Live demo: https://beamline.io/components/link-booking

A candidate's booking link for one stage of one job: a column with the job, the stage's length, who they meet (each with their role), where and what the interview covers (optional agenda, each part with its minutes); the month with only its open days; that day's times in the candidate's own zone (changeable) with the company's time beside each, and the day said when it differs; the chosen time from start to end in their zone and the company's, then their details (name, email for the invite, optional phone); then Book, which sends one booking however often it is pressed (the request carries a key formed with the draft, so a repeat is the same request). A time someone took meanwhile is struck where it stood on the warning tone with the nearest open times one tap each. Once booked: both clocks, a reference, and the calendar invite's delivery on a line of its own (sending, delivered, or bounced with Send again; the booking stands either way); Pick another time moves the booking with the same guard; Cancel the interview sits in the menu with a reason and a confirm; a cancelled booking can be booked again. A closed link says why.

## Use it for

- A link a person outside the team opens to book one meeting the team defined: an interview, a demo, a site visit.
- Where the booker and the team are in different time zones and both clocks matter, and where a double submit must never double-book.

## Not for

- Booking a practice's services with a practitioner and a place ([client-booking](https://beamline.io/components/client-booking)).
- Arranging a team's own calendar ([team-calendar](https://beamline.io/components/team-calendar)).

## Anatomy

- header: the tool's mark, Book your <stage> (Move your <stage> when rescheduling)
- about (a column beside the choice): the job and company, the company's zone, length, who (initials, name, role), where, The interview (agenda with minutes)
- when: the month with only open days, the zone choice, the day's times each with the company's time beside and the day said when it differs
- summary: the chosen day, start–end in the candidate's zone and in the company's
- details: name, email (the invite goes there), optional phone; a taken time with the nearest open ones; Book <day>, <time>
- booked: status, reference, the menu (Cancel the interview), both clocks, the invite's delivery line, Pick another time
- cancel: what happens, an optional reason, Keep it or Cancel the interview

## States

- picking mid-way, open times loading, failed with Try again, none this month
- booking (Book busy; more presses send nothing new), booked, moved, failed to book (details kept)
- taken meanwhile: struck, nearest offered
- invite sending, delivered, bounced with Send again
- cancelling, cancel failed, cancelled with Book again
- link closed
- phone: one column
- right to left: mirrored
- reduced motion: through the tokens

## Keyboard

- Tab through the calendar (arrows move days), the zone, each time, the details and Book; Enter or Space picks a time

## Motion

Nothing runs at rest.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `company` (required) | `string` | — | The hiring company, said beside its times and in the header. |
| `product` | `string` | — | The hiring tool's name, for the mark. |
| `booked` (required) | `BookedStage` | — |  |
| `timezone` (required) | `string` | — | The company's IANA zone. |
| `candidateTimezone` | `string` | — | The candidate's zone at first (the browser's, or what the link knows); they can change it. Default: the company's. |
| `zones` | `string[]` | — | More zones offered in the zone choice. |
| `loadSlots` (required) | `(span: { from: string; to: string; }) => Promise<OpenSlot[]>` | — | Open starts between two days (YYYY-MM-DD, inclusive, in the candidate's zone). A rejection is said with its reason and Try again. |
| `onBook` (required) | `(request: LinkBookingRequest) => Promise<LinkBookingAnswer>` | — | Books (or moves) the time. Must treat a repeated `key` as the same request. Reject only when nothing could be booked: the reason is said and the details kept. |
| `booking` | `LinkBookingRecord \| null` | — | The booking this link already holds (controlled), or null before one is made. |
| `defaultBooking` | `LinkBookingRecord \| null` | — |  |
| `onBookingChange` | `((booking: LinkBookingRecord \| null) => void)` | — |  |
| `invite` | `InviteDelivery \| null` | — | The invite's delivery for the current booking, as the host learns it. |
| `onResendInvite` | `(() => void)` | — |  |
| `onCancel` | `((bookingId: string, reason: string) => Promise<void>)` | — | Cancels the booking; reject with the reason when it couldn't be cancelled. |
| `contact` | `Partial<LinkContact>` | — | Details the link already knows. |
| `phoneCountry` | `string` | — | The country the phone field starts on (ISO code). |
| `defaultDay` | `string` | — | The day and start picked at first (a link reopened mid-way). |
| `defaultSlot` | `string` | — |  |
| `today` | `string` | — | Today in the candidate's zone (YYYY-MM-DD): no day before it is offered. Default: today. |
| `closed` | `string \| null` | — | The link no longer books (used, expired, the stage closed): the reason. |
| `timeFormat` | `"12h" \| "24h"` | — |  |
| `className` | `string` | — | Classes on the documented visual root; no override by default. |
| `style` | `CSSProperties` | — | Inline styles on the documented visual root; no overrides by default. |
| `ref` | `Ref<HTMLDivElement>` | — | Receives the documented native target or imperative handle; omitted by default. |

## Built from

- [Alert](https://beamline.io/components/alert.md)
- [Avatar](https://beamline.io/components/avatar.md)
- [Bottom sheet](https://beamline.io/components/bottom-sheet.md)
- [Button](https://beamline.io/components/button.md)
- [Calendar](https://beamline.io/components/calendar.md)
- [Combobox](https://beamline.io/components/combobox.md)
- [Dropdown menu](https://beamline.io/components/dropdown-menu.md)
- [Input](https://beamline.io/components/input.md)
- [Label](https://beamline.io/components/label.md)
- [Phone input](https://beamline.io/components/phone-input.md)
- [Skeleton](https://beamline.io/components/skeleton.md)
- [Spinner](https://beamline.io/components/spinner.md)
- [Textarea](https://beamline.io/components/textarea.md)

## Dependencies

`lucide-react`

## Import

```tsx
import { LinkBooking } from "@beamline/link-booking";
```

## Get it

Link booking is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. [Get Beamline](https://beamline.io/checkout?pack=complete) · [Connect your agent](https://beamline.io/connect)

## More in HR & payroll

- [Shift planner](https://beamline.io/components/shift-planner): A workplace's week of staff shifts against what it needs: a row per person with their week's hours against their contract, each day a 24-hour track with…
- [Shift rotations](https://beamline.io/components/shift-rotations): Rotating shift patterns from pattern to people: a pattern of one to four weeks painted day by day with a shift template, a rest day or nothing (pick the…
- [Roster publishing](https://beamline.io/components/roster-publish): The week's roster before it goes out: areas down the side and days across, each shift a chip with who works it and its hours, its state its tone (not…
- [My shift](https://beamline.io/components/my-shift): The worker's own shift on their phone: today drawn to scale (the plan's areas as blocks on an hour axis, under them what was worked: on-plan time in…
- [Timesheet review](https://beamline.io/components/timesheet-review): Timesheets for a manager: the day's counts at the head (scheduled, on shift, late, on break, to approve), the ones that filter being buttons, an…
- [Hours ledger](https://beamline.io/components/hours-ledger): One worker's pay cycle of shifts, for the worker or their payroll admin: the wall-clock span and the paid hours as separate columns, a night shift…
- [Payroll run](https://beamline.io/components/payroll-run): A pay period from report to submission, one payroll account at a time (a worker on two accounts is on both runs, never combined): the workers on one…
- [Payroll cycles](https://beamline.io/components/payroll-cycles): The client's side of an outsourced payroll across countries: every entity's current cycle on one board, its stage drawn as steps, the one thing that…
- [Payroll approvals](https://beamline.io/components/payroll-approvals): Payroll approvals for a company paying through a payroll provider. Expenses are split by whose move it is (you, another approver, the employee answering…
- [Benefit changes](https://beamline.io/components/benefit-changes): An employee's benefit changes after a life event. The centre puts their turn first: each task (a proof to upload, with its deadline in the warning tint…
- [Hiring pipeline](https://beamline.io/components/hiring-pipeline): A recruiting team's pipeline across every open job. Stage groups (reviewing, interviewing, closing) are counted across jobs above job sections that fold…
- [Recruiter home](https://beamline.io/components/recruiter-home): A recruiter's own work, in one place. Upcoming interviews with who sits in, today's first; feedback owed, overdue first and on the danger tone, written…
- [Stage reports](https://beamline.io/components/stage-reports): Reports on how applications move through stages, built from each application's stage intervals. By week: applications present in each stage (or from each…
- [Team & members](https://beamline.io/components/team-members): The people page of a workspace: seats used against the plan, members and pending invitations in one list with search and a role filter, role changes that…

Part of [Beamline UI: polished, editable React components and complete screens for custom applications](https://beamline.io/). [Build your own style from any look; tokens, fonts, radii, motion; not only colours](https://beamline.io/docs/customize).
