feat: add configurable pre-chat form for collecting user info (#17)#33
feat: add configurable pre-chat form for collecting user info (#17)#33anurag629 merged 2 commits intocodercops:devfrom
Conversation
…conversation Implements codercops#17. Adds a pre-chat form that appears before the chat starts, supporting text, email, select, and textarea fields with client-side validation. Form data is persisted per session and sent to the server as userData, which is injected into the system prompt for AI context. Made-with: Cursor
|
@Ashok161 is attempting to deploy a commit to the CODERCOPS Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| display: flex; | ||
| flex-direction: column; | ||
| overflow: hidden; | ||
| min-height: 0; |
There was a problem hiding this comment.
This overflow: hidden is what's making the page unresponsive. The inner .cc-messages has overflow-y: auto to handle scrolling, but this parent is clipping it — ends up causing layout thrashing in the Shadow DOM and the page freezes.
Either remove overflow: hidden here (.cc-messages handles its own scrolling already) or better — don't add this wrapper at all when preChatForm isn't configured. Right now every widget instance gets this extra div even if they never use the form.
Was this intentional? What were you trying to solve with it?
There was a problem hiding this comment.
No, the overflow: hidden wasn't intentional — I added the wrapper to share a container between the messages list and the pre-chat form for toggling visibility, but didn't realize the overflow clipping would cause layout thrashing inside the Shadow DOM. I've fixed it by making the wrapper conditional (only created when preChatForm is enabled) and removed overflow: hidden entirely since .cc-messages already handles its own scrolling.
packages/widget/src/dom/panel.ts
Outdated
| // Messages wrapper (shared container for messages and pre-chat form) | ||
| this.messagesContainer = document.createElement('div'); | ||
| this.messagesContainer.className = 'cc-messages-wrapper'; | ||
| this.el.appendChild(this.messagesContainer); |
There was a problem hiding this comment.
This wrapper gets added to every panel regardless of whether preChatForm is configured. The website's popup widget and inline demo don't use pre-chat at all, but they still get this extra DOM layer + the broken overflow styling.
Can you make this conditional? Only create the wrapper when pre-chat is enabled, otherwise just append Messages directly to this.el like before.
| /* Messages area */ | ||
| .cc-messages { | ||
| flex: 1; | ||
| flex: 1 1 0; |
There was a problem hiding this comment.
flex: 1 and flex: 1 1 0 are the same thing — can you revert this? Keeps the diff cleaner.
packages/widget/src/widget.ts
Outdated
| message: text, | ||
| pageContext, | ||
| locale: this.config.locale, | ||
| userData: this.userData, |
There was a problem hiding this comment.
This sends userData on every single message. It only needs to go once — the server injects it into the system prompt which sticks around for the whole conversation. Maybe track a userDataSent flag and skip it after the first message?
| @@ -136,16 +158,15 @@ export class Widget { | |||
| } | |||
There was a problem hiding this comment.
Quick question — how did you test this? The popup widget on the site loads from CDN at v0.2.0 (doesn't have your changes), and the inline LiveDemo doesn't pass preChatForm config. So the form won't show up on the Vercel preview at all.
Could you share a screenshot or recording of it working locally?
There was a problem hiding this comment.
The CDN popup is on v0.2.0 and the inline demo doesn't pass preChatForm, so yeah, nothing shows on the Vercel preview. I tested locally by adding autoOpen: 0 and the preChatForm config to dev.html, built with npm run build, and served it with npx serve:
All four field types render correctly, required markers show up, validation works (tried submitting empty + invalid email), and the preChatSubmit event fires with the right data.
packages/widget/src/dom/input.ts
Outdated
| } | ||
|
|
||
| setVisible(visible: boolean): void { | ||
| this.area.style.display = visible ? '' : 'none'; |
There was a problem hiding this comment.
Minor thing — toggling style.display directly can get messy if something else touches it later. The rest of the widget uses CSS classes for visibility (like cc-visible on the panel). Maybe use a class toggle here too? Same for messages.setVisible().
There was a problem hiding this comment.
True. I Switched both messages.setVisible() and input.setVisible() to toggle a cc-hidden class instead of touching style.display directly.
| @@ -0,0 +1,192 @@ | |||
| import type { PreChatField } from '../widget.js'; | |||
There was a problem hiding this comment.
No tests in this PR — the issue had 8 test cases listed in the acceptance criteria. Can you add at least the core ones? Field rendering, required field validation, email validation, and the show/skip form logic. Check packages/widget/tests/dom/ for the existing patterns.
There was a problem hiding this comment.
Will add the test cases
…ss-based visibility, add tests
Summary
Implements #17. Adds a configurable pre-chat form that appears before the conversation starts, letting widget owners collect user information (name, email, topic, etc.) upfront — a table-stakes feature for support and sales use cases.
What's included
prechat-form.ts) — renders inside the existing panel with text, email, select, and textarea field typessessionStorageper session, so page refresh doesn't re-show ituserDatasent with every chat request and injected into the system promptmessagefield is included, it's auto-sent as the first user message after form submitonPreChatSubmitcallback andpreChatSubmiteventFiles changed
packages/widget/src/widget.tspackages/widget/src/dom/prechat-form.tspackages/widget/src/dom/panel.tspackages/widget/src/dom/messages.tssetVisible()methodpackages/widget/src/dom/input.tssetVisible()methodpackages/widget/src/storage.tspackages/widget/src/styles/widget.csspackages/widget/src/i18n.tspackages/widget/src/api/types.tsuserDatafield inWidgetChatRequestpackages/server/src/handler.tsuserDatainto system promptpackages/server/src/config.tsuserDatain Zod request schema.changeset/prechat-form.mdwidget: minor,server: patch)Verification
pnpm -r typecheck— zero errorsnpx vitest run— 102/102 tests pass, no regressionsCloses #17