Client forms

A React block (a whole screen) in Beamline's Salon & fitness app.

A salon's or spa's client forms and who they ask: the forms down the side with where each stands (on, set up and off, not set up yet), the open one beside them. Its policy (who fills it: booked clients, the team or anyone with the link; how often: every appointment or once per client; which appointments: all, or chosen categories and services; after it is sent: no review, staff review, or review and signature) is tried on the coming week: every appointment lights when it would ask and the rest say why not in place (not covered, filled on a date, asked at an earlier visit, by link). Pressing one opens its reason with the change that would make it ask, or stop asking. Once per client is refused for a link, said beside it; being set up and being on are said apart; a save is a new version and forms already filled keep theirs. Two more parts travel with it: FormFields, a form's fields each with Required, From profile (filled from the client profile and written back, with its property) and In automations as three separate switches, beside the form as one client sees it, a test submission saying the submission saved and the profile write apart; and ArrivalForms, the day's arrivals with a form still missing, where Fill out here, Copy link and Send by text are three effects kept on the form's trail, none of them marking it done (a failed text says why), filled only when the submission arrives.

Use it for

  • Setting up a consent, intake, patch-test or feedback form and deciding who it asks: salons, spas, clinics, studios.
  • Checking why a client was or wasn't asked for a form at an appointment.
  • FormFields: deciding which answers fill and update the client profile, which are required and which automations may use.
  • ArrivalForms: the front desk getting a missing consent or intake form filled as the client arrives.

Not for

  • Building the form's fields (a form builder).
  • Collecting the answers at the appointment (the client's own form screen).
  • Why a time can't be booked (availability-layers).

Anatomy

  • header: the product's mark and the title
  • form list (nav): each form's name and where it stands (On, Set up · off, Not set up yet)
  • sheet head: the form's name, its version and whether anyone is asked now, and the Asking switch (on and off, apart from saving the policy)
  • choices: who fills it, how often (once per client refused for a link, said beside it), which appointments (all, or chosen categories and services), after it's sent (radio cards)
  • the week: a column per day (a row per day on a phone); each appointment a button with its time, service, client and its answer in place: Asks (the accent edge; dashed while off or unsaved: would ask), or why not
  • count: how many of the week's appointments ask (a rolling figure)
  • an opened appointment: who and when, why, and the change: Ask for its service too / All of its category, or Stop asking for it
  • bar (sticky, while there is something to save or say): the saved or failed words, Discard changes and Save policy
  • FormFields: the form's fields (name, kind; Required, From profile, In automations; the profile property and filled from it and written back), Undo and Save fields; As the client sees it, filled for one client (From <name>'s profile, Saved to the profile as …), Still needed, Submit as <name>, and the two results (Submission saved on v…; <name>'s profile updated / not updated with why, the submission kept)
  • ArrivalForms: the day and how many forms are missing; per arrival the time, client, service and staff; per form Still missing or Filled <time>, Fill out here, Copy link, Send by text (No mobile on file), and its trail (opened here, link copied, text sent, text not sent: why, submission arrived)

States

  • on and saved: lit appointments solid, the count says ask
  • set up, off: lit appointments dashed, said as would ask; the head says off
  • not set up yet: the switch disabled until the policy is saved
  • editing: the week answers each change at once, dashed until saved; the bar offers Save and Discard
  • by link: no appointment asks (By link); once per client disabled and said why
  • saved: a new version, said with what happens to forms already filled
  • save refused: the edit kept, said in the bar
  • look only (canManage false): the choices disabled, the permission said, no bar
  • loading: shaped skeletons; no forms: an empty state
  • phone: the list, then the form full width with Back; the week first, then the choices
  • right to left: the week and the choices mirror
  • reduced motion: through the tokens
  • FormFields: a field no profile property takes (From profile off, said)
  • FormFields: a required field left empty holds the test submission and is named
  • FormFields: profile write refused (the submission kept, said apart)
  • ArrivalForms: a text that couldn't go; no mobile on file; filled when the submission arrives; every form in

Keyboard

  • Tab through the list, the switch, the choices and each appointment; Enter or Space opens an appointment's reason
  • In the reason: Tab to its change and Close

Motion

An appointment's lit edge fades in or out as the policy changes (opacity); the count rolls (slot-text); an opened reason and a notice fade in. Nothing runs at rest.

Props

PropTypeDefaultDescription
formsClientForm[]—The forms, controlled with onFormsChange; or defaultForms.
defaultFormsClientForm[]—The starting forms when uncontrolled.
onFormsChange(forms: ClientForm[]) => void—After a save or a switch.
openstring—The open form's id.
defaultOpenstring—Initial open state when uncontrolled; defaults to false.
onOpenChange(id: string) => void—Reports an open-state change; no callback by default.
categories (required)FormCategory[]—The menu's categories ({ id, name }).
services (required)FormService[]—The services ({ id, name, categoryId }).
appointments (required)FormAppointment[]—The coming appointments the policy is tried on (a week is plenty).
location (required)string—Where those appointments are, said over the week.
days (required)string[]—The days drawn, in order ("2026-11-06" …); a day with no appointments says Closed.
onSave(form: ClientForm) => Promise<unknown>—Save a form's policy; resolve once saved. The block raises the version. Reject to keep the edit.
onEnabledChange(id: string, enabled: boolean) => Promise<unknown>—Turn asking on or off for a saved form. Reject to leave it as it was.
canManageboolean—false: the person may look but not change forms.
loadingboolean—Shaped skeletons while the forms load.
productstring—Your product's name, shown as its mark.
classNamestring—Classes on the documented visual root; no override by default.
refRef<HTMLDivElement>—Receives the documented native target or imperative handle; omitted by default.
FormFields: fields / properties / sample / onSave / onTestSubmitFormField[] / ProfileProperty[] / { name, values } / (fields) => Promise / (answers) => Promise<SubmissionResult>—The fields with their three settings, the profile's properties, a client the preview is filled for; a test submission's result carries the submission and the profile write apart.
ArrivalForms: arrivals / onArrivalsChange / onFillHere / onLink / onSendText / location / date / nowArrival[] / (arrivalId, formId) => Promise / … => Promise<string> / … => Promise—The day's arrivals with their forms and trails. The three actions add a step each and never mark a form done; your app sets filledAt and a filled step when the submission arrives. Reject onSendText with the reason a text wasn't sent.

Built from

Dependencies

lucide-react

Import

import { ClientForms, FormFields, ArrivalForms } from "@beamline/client-forms";

Get it

Client forms is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. Get Beamline · Connect your agent

More in Salon & fitness

  • Workout planner: A training plan a person lives in: the program's next session with its estimate and Start, an exercise replaced for this session only or for every later…
  • Workout logger: A live training session: every exercise's sets as target-table rows with a done column; marking a set done fills its shape and starts the rest by itself…
  • Training progress: A person's training history: the headline counts (weeks in a row, days since the last workout, workouts this month), a month calendar that names each…
  • Program setup: A training program's setup and living settings: the intake (one question per step, the week drawn as you answer, a failed generation keeping every…
  • Protocol builder: A practitioner's reusable protocol and the client copies made from it. Foods and habits each carry a written intent (Include, Reduce, Exclude) in its…
  • Nutrition library: A nutrition practice's library. Recipes: ingredients with grams and servings, nutrients per serving summed (energy, protein, carbohydrate, fat, fibre), a…
  • Packages & memberships: Prepaid packages and series, built: the packages down the side (version and how many sold, or not on sale yet), the open one beside them. Its price is a…
  • Instructor finder: Finding a flight instructor. Search by name or airfield, filter by what you want to learn (each subject with how many teach it nearby), by distance, and…
  • Flight logbook: A pilot's logbook. Total time (with hours brought forward from earlier logbooks), PIC, night, the last 90 days and how many entries are still incomplete…

Part of Beamline UI: polished, editable React components and complete screens for custom applications. Build your own style from any look; tokens, fonts, radii, motion; not only colours.