React Terminbuchung, die Zeitzonen richtig behandelt
React Terminbuchung klingt nach einem Kalender plus ein paar Buttons, und die meisten Tutorials hören genau da auf. Dann bucht jemand in Berlin deinen Host in New York um 3 Uhr nachts Ortszeit, jemand schnappt sich einen Slot, der in zehn Minuten beginnt, zwei Leute bestätigen dasselbe 14-Uhr-Gespräch, und auf dem Smartphone liegt das Zeitraster unter einem Sticky Header, an den niemand herankommt. Dieser Guide baut den Ablauf in drei Schritten (Datum, Zeitslot, Details) mit Wingo UI: die Zeiten des Hosts in seiner Zeitzone, vergebene Slots, Mindestvorlaufzeit, eine Prüfung auf dem Server und ein Layout fürs Smartphone. Am Ende steht, wann ein eingebetteter Hosted-Scheduler die bessere Wahl ist.
Was braucht ein guter Ablauf für Terminbuchungen?
Frag nach einem React Appointment Booking Calendar oder einem shadcn Booking Calendar, und die übliche Antwort ist ein Monatsraster neben einer Spalte mit Zeit-Buttons. Der Block calendar-20 (opens in a new tab) von shadcn/ui selbst (geprüft am 6. November 2026) ist genau das: feste Zeiten alle 15 Minuten von 9:00 bis 18:00 und eine fest eingetragene Liste gebuchter Tage. Die Form stimmt. Es fehlt aber alles, was darüber entscheidet, ob eine Buchung korrekt ist:
- Eine Frage pro Schritt. Erst das Datum, dann die Uhrzeit, dann Name und E-Mail. Auf dem Smartphone passt jeder Schritt auf einen Screen, und niemand muss an einem Formular vorbeiscrollen, um die Zeiten zu finden.
- Tage ohne Zeiten sind deaktiviert. Ein Wochenende, ein Tag nach Ende des Buchungsfensters oder ein Tag, an dem jeder Slot weg ist, sollte nicht anklickbar sein. Wenn der Kalender gleich auf dem ersten Tag mit einer freien Zeit startet, spart das einen Tap.
- Zeiten in der Zone der buchenden Person, Arbeitszeiten in der des Hosts. Der Host arbeitet in New York von 9 bis 17 Uhr. Wer in Berlin bucht, sollte Slots am Nachmittag und Abend sehen, und in Tokio können sie auf den nächsten Kalendertag rutschen.
- Mindestvorlaufzeit. Kein Slot beginnt früher als, sagen wir, vier Stunden ab jetzt.
- Eine Prüfung auf dem Server. Die UI blendet vergebene Slots aus, die Datenbank lehnt die zweite Buchung ab.
- Eine Bestätigung, mit der man etwas anfangen kann. Tag, Zeitraum und Zone, ein Meeting-Link, „Zum Kalender hinzufügen“ und eine Möglichkeit zum Verschieben.
Wie bekomme ich den ganzen Buchungsablauf in einer Komponente?
Die Vorlage Demo Booking Page deckt alle sechs Punkte auf einer Seite ab. Die Buchungskarte führt mit einem Stepper durch die Schritte Datum, Uhrzeit und Details, listet die Zeiten in der Zone der buchenden Person (aus dem Browser erkannt und änderbar), validiert jeden Schritt sofort und endet mit einer Bestätigung samt Buttons für Google Calendar, Outlook und .ics sowie einer Aktion zum Verschieben, die die Details behält.
$ npx wingo-ui@latest add demo-booking-pageInstallier sie und übergib deine Zeiten und einen Submit-Handler:
Die Props, auf die es bei der Buchung ankommt:
Ein Haken: Die Vorlage markiert manche Slots mit einer stabilen Pseudozufallsauswahl als vergeben, damit das Beispiel echt wirkt. Sie wird als Quellcode in dein Projekt kopiert, also ersetzt du für die Produktion diese taken-Prüfung durch deine echten belegten Zeiten (der nächste Abschnitt zeigt die Form). Die Vorlage ist Pro, ebenso Calendar, Time Picker und Timezone Select weiter unten; der Pro-Plan kostet $8 im Monat, $80 im Jahr oder einmalig $150.
Wie baue ich einen Time Slot Picker in React selbst?
Wenn die Buchung in deiner App lebt, etwa in einem Praxis-Dashboard oder einem Coaching-Tool, willst du vielleicht nur die Einzelteile. Der Calendar wählt den Tag, eine Liste von Buttons ist der Time Slot Picker, und der Timezone Select setzt die Zone. Die Vorlage exportiert ihre Slot-Berechnung als getDemoBookingSlots(day, options), du musst die Umrechnung zwischen Zonen also nicht selbst schreiben:
Das ist ein kompletter Time Slot Picker in React in unter 80 Zeilen. Vier Details darin erledigen die meiste Arbeit. disabled nimmt eine Funktion, ein Tag ist also genau dann aus, wenn er keinen freien Slot hat, und deaktivierte Tage bleiben fokussierbar, damit die Tastatur über sie hinweggehen kann. hideTaken: false schaltet die Beispielbelegung der Vorlage ab, sodass nur deine busy-Liste zählt. Der gecachte slotLookup ist wichtig, weil der Calendar disabled bei jedem Render für jeden sichtbaren Tag aufruft; übergib ein stabiles busy-Array (aus State oder deinem Daten-Hook), sonst wird der Cache jedes Mal zurückgesetzt. Und date am Timezone Select sorgt dafür, dass die Offsets in der Liste der Sommerzeit des gewählten Tages folgen, nicht der von heute.
$ npx wingo-ui@latest add timezone-selectWarum gehören die Zeiten des Hosts in seine Zeitzone?
Weil sich Offsets verschieben, und zwar nicht überall am selben Tag. 2026 hat Europa die Sommerzeit am 25. Oktober verlassen, die USA am 1. November, also lag Berlin in dieser Woche 5 statt 6 Stunden vor New York. Ein Host, der in New York von 9 bis 17 Uhr arbeitet, war im Oktober von 13:00 bis 21:00 UTC erreichbar und ist es seit dem 1. November von 14:00 bis 22:00 UTC. Speicherst du den UTC-Bereich aus dem Oktober, beginnt ab November jeder Slot auf der Uhr des Hosts eine Stunde zu früh. Speichere { timeZone: "America/New_York", start: 9, end: 17 }, berechne die Zeitpunkte für jeden Tag und schick start.toISOString() an den Server. Die Zone der buchenden Person dient nur der Anzeige.
Wann passt der Time Picker statt Slot-Buttons?
Ein React-Kalender mit Zeitslots zeigt feste Startzeiten, und das ist für öffentliche Buchungen richtig. Der Time Picker passt auf die andere Seite: wenn der Host seine Zeiten festlegt oder bei einem Anfrageformular, in dem jede Zeit innerhalb eines Fensters in Ordnung ist. min und max begrenzen das Fenster, minuteStep legt das Raster fest, und disabledTimes sperrt einzelne Zeiten wie eine Mittagspause oder gebuchte Slots:
Auf dem Smartphone öffnet er ein Bottom Sheet mit einrastenden Walzen, statt die Tastatur hochzuholen. Brauchst du Datum und Uhrzeit in einem Feld, schau in unseren Guide zum shadcn Date Time Picker und den Guide zum React Time Picker.
Wie verhindere ich Doppelbuchungen auf dem Server?
Vergebene Slots auszublenden ist nur ein Hinweis. Zwei Personen können die Seite um 9:00 laden und beide 14 Uhr bestätigen. Lass die Datenbank entscheiden. In Postgres lehnt ein Exclusion Constraint überlappende Zeiträume für denselben Host ab:
23P01 ist der Fehlercode von Postgres für eine Exclusion-Verletzung. Die Grenzen '[)' erlauben, dass eine Buchung um 14:30 endet und die nächste um 14:30 beginnt. Antwortet die Route mit 409, wirft das onSubmit von oben einen Fehler, die Vorlage zeigt den Text aus labels.failed, und die Person geht einen Schritt zurück, um eine andere Zeit zu wählen. Unser Guide zum Resource Scheduler nutzt denselben Constraint für Räume und Autos.
Wie sollte die Buchung auf dem Smartphone aussehen?
Hier helfen die Schritte am meisten. In der Demo Booking Page wird der Stepper zu einem kompakten Header „Schritt 1 von 3“, Zurück und Weiter sitzen in einer Leiste, die unten am Screen fixiert ist, und die Liste der Zeitzonen öffnet sich als Bottom Sheet. Die Kalenderzellen wachsen auf Touch-Geräten auf 44px, und ein Wischen wechselt den Monat. Beschränk die Slot-Liste auf zwei oder drei Spalten mit Buttons in voller Breite; eine Woche mit sieben Spalten voller Zeiten passt nicht auf 390px.
Wann sollte ich stattdessen einen Hosted-Scheduler einbetten?
Selbst bauen lohnt sich, wenn die Buchung zu deinen Produktdaten gehört. Brauchst du vor allem einen Link „Gespräch buchen“, kann ein Hosted-Scheduler am ersten Tag mehr: Er liest belegte Zeiten aus Google- oder Outlook-Kalendern, verschickt Bestätigungen und kümmert sich um Links zum Verschieben und Absagen. Team-Scheduling gibt es in den bezahlten Plänen. Ihre öffentlichen Preisseiten, geprüft am 6. November 2026:
Bette einen ein, wenn dir Kalendersync wichtiger ist als Design und du damit leben kannst, dass die Buchung in deren System liegt. Bau selbst, wenn du eigene Felder brauchst, dein eigenes Aussehen in Light und Dark Mode, Buchungen neben deinen Nutzern und Zahlungen in deiner Datenbank oder keine Gebühr pro Seat, wenn das Team wächst. Auch mit einem Embed anzufangen und umzuziehen, sobald die Buchung zu einem Kernfeature wird, ist ein vernünftiger Weg.
Weitere Screens, komplett von Anfang bis Ende gebaut, findest du in der Kategorie Build it und im Tutorial zum Next.js Admin Dashboard.
Wo fange ich an?
Öffne die Vorlage Demo Booking Page, wechsle die Zeitzone und geh die drei Schritte auf deinem Smartphone durch. Wenn sie passt, melde dich mit deinem Pro-Konto an, und npx wingo-ui@latest add demo-booking-page kopiert sie mit dem Calendar, dem Stepper und den Feldern, die sie nutzt, in dein Projekt, bereit für deine Zeiten und deine Route /api/bookings.
Häufige Fragen
Wie baue ich eine Seite für Terminbuchungen in React?
Teil sie in drei Schritte: ein Kalender, der nur Tage mit freien Zeiten aktiviert, eine Liste der Zeitslots für den gewählten Tag und ein kurzes Formular für die Details. Erzeuge die Slots aus den Wochenzeiten des Hosts, entferne vergebene und solche innerhalb der Mindestvorlaufzeit und bestätige die Buchung auf dem Server, bevor du den Erfolgsscreen zeigst.
Wie sollte ein Buchungskalender mit Zeitzonen umgehen?
Speichere die Zeiten des Hosts als Uhrzeiten in einer IANA-Zone wie America/New_York, nie als festen UTC-Offset. Rechne jeden Slot beim Rendern in die Zeitzone der buchenden Person um und schick die Buchung als ISO-Zeitstempel an deinen Server, damit die Zeitumstellung sie nicht verschieben kann.
Wie verhindere ich, dass zwei Leute denselben Zeitslot buchen?
Blende vergebene Slots in der UI aus, aber sieh das nur als Hinweis, denn zwei Personen können in derselben Sekunde bestätigen. In Postgres lehnt ein Exclusion Constraint auf einer tstzrange-Spalte überlappende Buchungen für denselben Host ab, und deine API beantwortet die unterlegene Anfrage mit 409.
Sollte ich Calendly oder Cal.com einbetten, statt die Buchung selbst zu bauen?
Bette einen davon ein, wenn du bald Kalendersync mit Google oder Outlook, Erinnerungen, Links zum Verschieben und Team-Routing brauchst und die Buchung nicht in deiner eigenen Datenbank liegen muss. Bau sie selbst, wenn die Buchung zu deinen Produktdaten gehört, eigene Felder oder ein eigenes Design braucht oder du keine Gebühr pro Seat zahlen willst.
Gibt es einen shadcn Booking Calendar mit Zeitslots?
Ja, der Block calendar-20 von shadcn/ui kombiniert seinen Calendar mit einer Spalte fester Zeiten im 15-Minuten-Takt und ein paar gebuchten Tagen, aber ohne Zeitzonen, Mindestvorlaufzeit oder Schritt für die Details. Wingo UI wird genauso als Quellcode installiert, und seine Demo Booking Page ergänzt die Zeitzonenrechnung, vergebene Slots, Mindestvorlaufzeit, Validierung und ein Layout fürs Smartphone.
- Buchung
- Kalender
- Zeitzonen
- Mobile UI
