SecretoCho
menu

component 28 / 28WORKING

SC Time Slot Selector

type
Code Component
platform
Framer
license
SecretoCho Design
needs JavaScript

demo · runs with JavaScript

fig 00 · live demo, ported from Time_Slot.tsx

Time-slot picker for forms: slots from start to end at an interval, converted from the organizer’s zone to the visitor’s (luxon), 12/24 h toggle, 148 zones, hidden input.

SC Time Slot Selector lays out bookable time slots between a start and an end time at a chosen interval, generated in the organizer’s time zone and shown in the visitor’s. The visitor can switch the time zone from a list of 148 zones and toggle 12- and 24-hour display; the chosen slot goes into a hidden input for the Framer form, either as HH:mm or as a full ISO timestamp.

The companion of SC Calendar Widget in the old site’s booking flow; it uses luxon for the zone maths.

  • Booking
  • UI
  • Internationalization

Main

Overview

Built With
React (hooks), luxon (DateTime), Intl.DateTimeFormat, Framer Code Component API
Layout Support
Fills the frame width; slots wrap
Orientation
Wrapped slot chips, then a row with the zone selector and the 12hr | 24hr toggle
Ideal Use Case
Booking and consultation forms with clients in other time zones

Tags

  • time slots
  • booking
  • time zone
  • luxon
  • 12-hour
  • 24-hour
  • form
  • hidden input

Code comment

Time_Slot.tsx has no doc comment: lines 202–207 hold only Framer’s annotations and the © line.

Dependencies

Technologies
luxon (third-party date library, imported as "luxon")
Notes
The visitor’s zone comes from Intl.DateTimeFormat().resolvedOptions().timeZone; zones outside the file’s list fall back to UTC.

Complexity

Logic Level
Medium (slot generation across zones, dropdown with click-outside, two formats)
Runtime Cost
Very Low (slots recomputed per render; one document mousedown listener)
Component Size
~17 KB TSX (17,049 bytes, 533 lines); 156 of the lines are the zone list
Notes
luxon is the only external dependency among the drafts.

Guide

Instructions

  1. Drop SC Time Slot Selector inside a Framer form.
  2. Set Start Time and End Time (HH:mm), the Interval (15 min … 4 hr) and the Origin Time Zone (yours).
  3. Choose Default to 12-Hour; the visitor can still toggle.
  4. Set Data Type (time → HH:mm in the visitor’s zone; text → ISO timestamp with offset) and Data Name.
  5. Style the accent, hover, background and text colours, the paddings, gap, font, sizes and border.

Examples / Presets

  • 30-minute slots

    interval
    30
  • 24-hour clock

    is12Hour
    false
  • ISO values

    dataType
    text (the hidden input holds the full ISO timestamp with offset)

Source defaults: 09:00–18:00, 60 min, origin Europe/Belgrade, 12-hour. The demo also carries an action “As in the booking flow” built from the owner’s instance on the old site’s earlier home page.

Mechanics

How it Works

  • Slots: generateTimeSlots parses start and end as HH:mm, builds luxon DateTimes for today in the origin zone, walks from start to end by the interval, re-zones each instant to the visitor’s zone and formats it “h:mm a” or “HH:mm”.
  • Value: for Data Type time the slot value is HH:mm in the visitor’s zone; for text it is the ISO string with offset.
  • Zone: the visitor’s zone is read once from Intl; if it is not in the file’s list of 148 zones, UTC is used. The zone pill opens a scrollable list; a document mousedown listener closes it on an outside click.
  • Toggle: the 12hr | 24hr segmented control changes the display format only.
  • Form: a hidden read-only <input type=time|text name=dataName> holds the selected value.

Performance & Tuning

  • Slots are recomputed on every render (no memo); with a 15-minute interval over a working day that is a few dozen DateTime objects — negligible.
  • luxon adds a library to the page; it is the only dependency.

Compatibility & Limits

  • Evergreen browsers with Intl time zones; luxon handles the zone maths.
  • The zone list is fixed in the file (148 zones); a visitor’s zone outside it shows as UTC until they pick another.
  • The Font control is a Framer font object, but the file applies props.font directly as font-family: with a Font value selected the family may not apply (the default string “Inter, sans-serif” does).
  • The zone box keeps a hard-coded #fff background (its text is inherited) and the inactive 12hr | 24hr segments #fff / #333, and the zone box draws its border whether or not border.show is on.
  • The zone list is position: absolute at top 40 inside a wrapper that is not positioned, so it opens relative to the nearest positioned ancestor and can land over the slots.
  • With Data Type time the form receives HH:mm in the visitor’s zone but not the zone itself; use text (ISO with offset) when the zone matters.
  • Zone names must match the list exactly (it has Europe/Kiev, Asia/Kolkata, Asia/Kathmandu); a browser that reports another spelling (Asia/Calcutta, Asia/Katmandu, Europe/Kyiv) starts the visitor on UTC.
  • A picked slot’s hidden value stays after a zone change while no slot shows as selected.
  • Labels (“Time Zone:”, “12hr”, “24hr”) are English strings in the file.

Quality

Accessibility

  • Slots are <div role="button"> without tabIndex or keyboard handlers; the zone list and toggle are clickable divs.
  • Selected and hovered states are colour only; the hidden input is the only form control.

Security & Privacy

  • No network calls, no storage, no permissions.
  • Third-party library: luxon (DateTime) for zone conversion and formatting.
  • Reads the device time zone through Intl.DateTimeFormat (no permission prompt); one document mousedown listener while mounted.

Reference

Props

nametypedefaultdescription
startTimestring09:00Start Time (HH:mm, origin zone).
endTimestring18:00End Time (HH:mm, origin zone).
intervalenum60Interval. 15 min | 30 min | 1 hr | 2 hr | 4 hr (15, 30, 60, 120, 240 minutes).
originTimeZoneenumEurope/BelgradeOrigin Time Zone. One of the file’s 148 IANA zones.
is12HourbooleantrueDefault to 12-Hour.
accentColorcolor#3B82F6Accent Color (selected slot, active zone, active toggle).
hoverColorcolor#f0f0f0Hover Color.
backgroundColorcolor#fffBackground (slots and the zone list).
activeTextColorcolor#ffffffActive Text (on the accent).
textColorcolor#4D4D4DText Color.
paddingSlotstring10px 8pxSlot Padding (CSS string).
paddingTimeZonestring6px 10pxTimeZone Padding (CSS string).
gridGapstring10pxGrid Gap between slots (CSS string).
fontFontStyleInter, sans-serifFont (see the note under this table).
fontSizenumber15Font Size Head 8–36 px (slots).
fontSizeBodynumber13Font Size Body 8–36 px (zone row and toggle).
borderobjectshow=true, width=1, style=solid, color=#d2d2d2Border. Show, Width 0–4, Solid | Dashed | Dotted, Color.
dataTypeenumtimeData Type. time | text for the hidden input’s type and value format.
dataNamestringTimeData Name. The form field name.

font is declared as ControlType.Font but used as a plain font-family string (style={{ fontFamily: props.font }}); only the default string works as intended. The interval control has no title in the file (Framer shows the prop name).

Notes & Tips

  • Set Origin Time Zone to where the meeting is held; the visitor sees their own times.
  • Use Data Type text when the back end needs the date and offset, not just the clock time.
  • Pair it with SC Calendar Widget: the slot’s ISO value carries today’s date, so the calendar supplies the day.

Troubleshooting / FAQ

The zone shows UTC although my system zone is set

The browser’s name for the zone is not in the file’s list (it has Asia/Kolkata, Asia/Kathmandu and Europe/Kiev; some browsers report Asia/Calcutta, Asia/Katmandu or Europe/Kyiv); pick the nearest city from the dropdown.

Fewer slots than expected

End Time is inclusive only when it lands on the interval; 18:00 with 60-minute steps from 09:00 gives ten slots.

The font does not change

The Font control’s object is applied as font-family directly; use a plain family string or fix the mapping.

The zone box stays white on a dark theme

Its background (#fff) and the inactive segment colours (#fff / #333) are hard-coded; the slots and the zone dropdown list follow Background and Text Color.

The zone list opens over the slots

The list is absolutely positioned at top 40 and the component has no positioned wrapper; wrap it in a layer with position: relative or fix the file.

Source

Header comment

Time_Slot.tsx has no doc comment: lines 202–207 hold only Framer’s annotations and the © line.

props [REF]

Key excerpt

Slots are generated in the organizer’s zone and converted to the visitor’s: luxon walks from start to end by the interval, re-zones each instant and formats it 12- or 24-hour.

Time_Slot.tsx · lines 169–201 · tsx
function generateTimeSlots(    start,    end,    interval,    originZone,    userZone,    is12Hour,    dataType) {    const slots = []    let [startHour, startMinute] = start.split(":").map(Number)    let [endHour, endMinute] = end.split(":").map(Number)    const startDT = DateTime.fromObject(        { hour: startHour, minute: startMinute },        { zone: originZone }    )    const endDT = DateTime.fromObject(        { hour: endHour, minute: endMinute },        { zone: originZone }    )    for (let dt = startDT; dt <= endDT; dt = dt.plus({ minutes: interval })) {        const local = dt.setZone(userZone)        slots.push({            display: formatTime(local, is12Hour),            value:                dataType === "time" ? formatTime(local, false) : local.toISO(),        })    }    return slots}

Credits

Credits

© SecretoCho Design 2025 — stated in the file (line 206).

license
SecretoCho Design

SecretoCho Design 2025

Disclaimer

Proves

Hiring a design engineer?

I’m open to senior design engineer roles: remote from Belgrade, or relocation with visa sponsorship. Write to me, or read the CV first. Client work stays selective, one project at a time.

sc@secretocho.design

read the CV · LinkedIn