diff --git a/app/assets/javascripts/shared/meetings-2/due-date.js b/app/assets/javascripts/shared/meetings-2/due-date.js
new file mode 100644
index 00000000..e83f21d4
--- /dev/null
+++ b/app/assets/javascripts/shared/meetings-2/due-date.js
@@ -0,0 +1,75 @@
+// Validation for the not guilty plea date field on the meetings-2 due-date page.
+// Two scenarios: mandatory field, and the date must be in the past.
+function validateForm() {
+ // Clear previous errors
+ $('#error-form-group').removeClass('govuk-form-group--error');
+ $('#error-message-1').remove();
+ $('#ngp-date').removeClass('govuk-input--error');
+ $('#error-summary').remove();
+
+ var dateValue = document.getElementById('ngp-date').value;
+ var dateDatePicker = $('#ngp-date-picker');
+ var errorMessage = validateDate(dateValue);
+
+ if (errorMessage) {
+ // Error form group styling
+ $('#error-form-group').addClass('govuk-form-group--error');
+
+ // Error message below the label, before the date picker
+ dateDatePicker.before('
Error: ' + errorMessage + '
');
+
+ // Error input field styling
+ $('#ngp-date').addClass('govuk-input--error');
+
+ // Error summary at the top
+ $('form').before(
+ '
'
+ );
+ $('#error-summary').focus();
+
+ return false;
+ }
+
+ return true;
+}
+
+function validateDate(dateString) {
+ // Mandatory field
+ if (!dateString || dateString.trim() === '') {
+ return 'Enter the date the defendant pleaded not guilty';
+ }
+
+ // Check format (DD/MM/YYYY)
+ var datePattern = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
+ var match = dateString.match(datePattern);
+
+ if (!match) {
+ return 'Enter the date in the correct format, like 20/08/2026';
+ }
+
+ var day = parseInt(match[1], 10);
+ var month = parseInt(match[2], 10);
+ var year = parseInt(match[3], 10);
+
+ // Check valid month
+ if (month < 1 || month > 12) {
+ return 'Enter a real date';
+ }
+
+ // Check valid day for month
+ var daysInMonth = new Date(year, month, 0).getDate();
+ if (day < 1 || day > daysInMonth) {
+ return 'Enter a real date';
+ }
+
+ // Must be today or in the past
+ var inputDate = new Date(year, month - 1, day);
+ var today = new Date();
+ today.setHours(0, 0, 0, 0);
+
+ if (inputDate > today) {
+ return 'The date the defendant pleaded not guilty must be today or in the past';
+ }
+
+ return null; // No error
+}
diff --git a/app/assets/javascripts/shared/meetings-2/meeting-due-date.js b/app/assets/javascripts/shared/meetings-2/meeting-due-date.js
new file mode 100644
index 00000000..f1b5b29d
--- /dev/null
+++ b/app/assets/javascripts/shared/meetings-2/meeting-due-date.js
@@ -0,0 +1,59 @@
+// Validation for the meetings-2 meeting-due-date page.
+// The radio question is mandatory. If "By another date" is selected, the
+// conditional date field is also mandatory.
+function validateForm() {
+ // Clear previous errors
+ $('#error-form-group-1').removeClass('govuk-form-group--error');
+ $('#error-form-group-2').removeClass('govuk-form-group--error');
+ $('#error-message-1').remove();
+ $('#error-message-2').remove();
+ $('#meeting-due-date').removeClass('govuk-input--error');
+ $('#error-summary').remove();
+
+ var selectedOption = $('[name=meetingDueOption]:checked').val();
+ var dueDateValue = document.getElementById('meeting-due-date').value;
+
+ var optionError = null;
+ var dateError = null;
+
+ // The radio question is mandatory
+ if (!selectedOption) {
+ optionError = 'Select when the offer is due for the CPS pre-trial meeting';
+ } else if (selectedOption === 'other-date' && dueDateValue.trim() === '') {
+ // Conditional date field is mandatory when "By another date" is chosen
+ dateError = 'Enter the meeting offer due date';
+ }
+
+ if (optionError || dateError) {
+ // Error summary at the top
+ var summaryItems = '';
+ if (optionError) {
+ summaryItems += '