fix(demo): preload the Cal.com booking embed while the visitor fills the form (#5616)

* fix(demo): preload the Cal.com booking embed while the visitor fills the form

The embed script, booker iframe, and its assets only started downloading
after the visitor pressed Continue, so the calendar took several seconds
to appear. Warm the whole path on first form focus via the embed's
documented preload instruction (hidden ?preload=true iframe caches the
booker assets) plus a preconnect to app.cal.com. Nothing Cal.com-related
loads at initial page load, so Lighthouse/LCP are untouched.

* fix(demo): retry embed warm-up on failure, preconnect only on first focus

Reset the preload guard when embed.js fails to load so a later focus can
retry, and move the app.cal.com preconnect from render into the
focus-triggered preload path so initial page load makes zero Cal.com
connections.
This commit is contained in:
Waleed
2026-07-11 19:51:51 -07:00
committed by GitHub
parent 0cc6ed61d3
commit a2f868c397
3 changed files with 40 additions and 2 deletions
@@ -3,10 +3,24 @@
import { type CSSProperties, useEffect, useRef, useState } from 'react'
import { chipBorderShadowRing, cn } from '@sim/emcn'
import dynamic from 'next/dynamic'
import { preconnect } from 'react-dom'
import { DemoForm, type DemoLead } from '@/app/(landing)/demo/components/demo-form'
const importScheduler = () => import('@/app/(landing)/demo/components/demo-scheduler')
/**
* Warm the entire booking path while the visitor fills the form: preconnect to
* app.cal.com, then load the scheduler chunk, Cal.com's embed.js, and the
* booker iframe assets (via the embed's `preload` instruction). Fired on first
* form focus so nothing Cal.com-related competes with initial page load — the
* connection handshake overlaps the chunk import, and it all finishes long
* before the visitor submits.
*/
function preloadScheduler() {
preconnect('https://app.cal.com')
return importScheduler().then((m) => m.preloadCalEmbed())
}
/**
* Lazy-loaded so the Cal.com embed never enters the initial landing bundle - it
* loads only once a visitor reaches the booking step. `loading: () => null` (no
@@ -75,7 +89,7 @@ export function DemoBooking({ className }: DemoBookingProps) {
<div
className='w-full min-w-0 shrink-0'
inert={showScheduler}
onFocusCapture={() => void importScheduler()}
onFocusCapture={() => void preloadScheduler()}
>
<div ref={formRef} className='p-6 max-sm:p-5'>
<DemoForm onComplete={setLead} />
@@ -19,6 +19,30 @@ interface DemoSchedulerProps {
lead: DemoLead
}
let calEmbedPreloaded = false
/**
* Warm the Cal.com embed before the scheduler mounts. Loads `embed.js` and
* issues the embed's `preload` instruction, which fetches the booker in a
* hidden `?preload=true` iframe so its assets are already cached when the real
* embed renders on submit. Without this, nothing Cal.com-related starts
* downloading until the visitor presses Continue, which is why the calendar
* used to take several seconds to appear. Idempotent — repeat calls no-op
* while a warm-up is in flight or done, but a failed embed.js load resets the
* flag so a later focus can retry.
*/
export function preloadCalEmbed(): void {
if (calEmbedPreloaded) return
calEmbedPreloaded = true
getCalApi({ namespace: CAL_NAMESPACE })
.then((cal) => {
cal('preload', { calLink: CAL_LINK })
})
.catch(() => {
calEmbedPreloaded = false
})
}
/**
* Step 2 of the booking card - the Cal.com scheduler, prefilled from the form's
* {@link DemoLead}. Rendered inside the card chrome owned by {@link DemoBooking}
@@ -1 +1 @@
export { DemoScheduler } from './demo-scheduler'
export { DemoScheduler, preloadCalEmbed } from './demo-scheduler'