From b7a0ec62ba788bf8d86ac37b1f97957e45895f99 Mon Sep 17 00:00:00 2001 From: Nameless-Monster-Nerd Date: Thu, 30 Jul 2026 22:50:09 -0400 Subject: [PATCH] fix(widget): validate required checkboxes as accepted (#15135) Required checkbox fields in the pre-chat form now remain invalid unless they are checked. Other required field types keep their existing validation behavior, and the existing localized required message is reused. ## Closes Closes https://github.com/chatwoot/chatwoot/issues/15128 ## How to reproduce 1. Add a required checkbox custom attribute to the pre-chat form. 2. Check and then uncheck it. 3. Submit the form; submission is now blocked until the checkbox is checked. ## What changed - Use the FormKit accepted rule for required checkbox fields. - Map accepted validation failures to the existing pre-chat required message. --------- Co-authored-by: Nazmus Samir Co-authored-by: Sojan Jose --- .../widget/components/PreChat/Form.vue | 4 +- .../components/PreChat/specs/Form.spec.js | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 app/javascript/widget/components/PreChat/specs/Form.spec.js diff --git a/app/javascript/widget/components/PreChat/Form.vue b/app/javascript/widget/components/PreChat/Form.vue index 280f08363..224f787f9 100644 --- a/app/javascript/widget/components/PreChat/Form.vue +++ b/app/javascript/widget/components/PreChat/Form.vue @@ -187,7 +187,8 @@ export default { }; const validationKeys = Object.keys(validations); const isRequired = this.isContactFieldRequired(name); - const baseRules = isRequired ? [['required']] : [['optional']]; + const requiredRule = type === 'checkbox' ? 'accepted' : 'required'; + const baseRules = isRequired ? [[requiredRule]] : [['optional']]; if ( !validationKeys.includes(name) && @@ -293,6 +294,7 @@ export default { isValidPhoneNumber: $t('PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.VALID_ERROR'), email: $t('PRE_CHAT_FORM.FIELDS.EMAIL_ADDRESS.VALID_ERROR'), required: $t('PRE_CHAT_FORM.REQUIRED'), + accepted: $t('PRE_CHAT_FORM.REQUIRED'), matches: item.regex_cue ? item.regex_cue : $t('PRE_CHAT_FORM.REGEX_ERROR'), diff --git a/app/javascript/widget/components/PreChat/specs/Form.spec.js b/app/javascript/widget/components/PreChat/specs/Form.spec.js new file mode 100644 index 000000000..3bfeb3573 --- /dev/null +++ b/app/javascript/widget/components/PreChat/specs/Form.spec.js @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest'; + +import Form from '../Form.vue'; + +const getValidation = Form.methods.getValidation; + +const validationFor = (field, required) => + getValidation.call( + { + isContactFieldRequired: () => required, + }, + field + ); + +describe('PreChat Form getValidation', () => { + it('returns accepted for a required checkbox', () => { + expect(validationFor({ type: 'checkbox', name: 'checkbox' }, true)).toEqual( + [['accepted']] + ); + }); + + it('returns optional for an optional checkbox', () => { + expect( + validationFor({ type: 'checkbox', name: 'checkbox' }, false) + ).toEqual([['optional']]); + }); + + it('returns required for a required text field', () => { + expect(validationFor({ type: 'text', name: 'text' }, true)).toEqual([ + ['required'], + ]); + }); + + it('combines required and type-specific validation rules', () => { + expect( + validationFor({ type: 'email', name: 'emailAddress' }, true) + ).toEqual([['required'], ['email']]); + }); +});