Skip to content

feat: add configurable pre-chat form for collecting user info (#17)#33

Merged
anurag629 merged 2 commits intocodercops:devfrom
Ashok161:dev
Mar 22, 2026
Merged

feat: add configurable pre-chat form for collecting user info (#17)#33
anurag629 merged 2 commits intocodercops:devfrom
Ashok161:dev

Conversation

@Ashok161
Copy link
Copy Markdown
Contributor

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

  • Form component (prechat-form.ts) — renders inside the existing panel with text, email, select, and textarea field types
  • Client-side validation — required field checks, email format validation, inline error messages
  • Submit button disabled state — button stays disabled until all required fields are filled
  • Session persistence — form completion stored in sessionStorage per session, so page refresh doesn't re-show it
  • Server integrationuserData sent with every chat request and injected into the system prompt
  • Personalization — welcome message includes user's name when provided
  • Auto-send — if a message field is included, it's auto-sent as the first user message after form submit
  • Callbacks & eventsonPreChatSubmit callback and preChatSubmit event
  • Backward compatible — form is skipped when not configured or when conversation history exists
  • Works in both popup and inline modes

Files changed

File Change
packages/widget/src/widget.ts Config interfaces, form lifecycle, state management
packages/widget/src/dom/prechat-form.ts New — form DOM component
packages/widget/src/dom/panel.ts Messages wrapper container, visibility controls
packages/widget/src/dom/messages.ts setVisible() method
packages/widget/src/dom/input.ts setVisible() method
packages/widget/src/storage.ts Per-session pre-chat completion persistence
packages/widget/src/styles/widget.css Pre-chat form styles (follows existing theme)
packages/widget/src/i18n.ts 5 new locale strings
packages/widget/src/api/types.ts userData field in WidgetChatRequest
packages/server/src/handler.ts Inject userData into system prompt
packages/server/src/config.ts userData in Zod request schema
.changeset/prechat-form.md Changeset (widget: minor, server: patch)

Verification

  • pnpm -r typecheck — zero errors
  • npx vitest run — 102/102 tests pass, no regressions

Closes #17

…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
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 21, 2026

@Ashok161 is attempting to deploy a commit to the CODERCOPS Team on Vercel.

A member of the Team first needs to authorize it.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chatcops-website Ready Ready Preview, Comment Mar 21, 2026 0:52am

Request Review

anurag629

This comment was marked as duplicate.

@anurag629 anurag629 dismissed their stale review March 21, 2026 08:50

Rewriting review

Copy link
Copy Markdown
Member

@anurag629 anurag629 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on this @Ashok161! The form component and storage logic look good overall. I found a few things that need fixing though — the main one is causing the page to freeze. See my comments below.

display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

// 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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay

/* Messages area */
.cc-messages {
flex: 1;
flex: 1 1 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flex: 1 and flex: 1 1 0 are the same thing — can you revert this? Keeps the diff cleaner.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

message: text,
pageContext,
locale: this.config.locale,
userData: this.userData,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

@@ -136,16 +158,15 @@ export class Widget {
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

prechat-form-open

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.

}

setVisible(visible: boolean): void {
this.area.style.display = visible ? '' : 'none';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add the test cases

Copy link
Copy Markdown
Member

@anurag629 anurag629 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All review items addressed — overflow fix, conditional wrapper, userData sent once, class toggle, tests added. Looks good, nice work @Ashok161!

@anurag629 anurag629 merged commit 3c74978 into codercops:dev Mar 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add configurable pre-chat form for collecting user info before conversation

2 participants