Skip to content

Add user displayed completion tracking to your Collapsible Sections

Using a lightweight JavaScript snippet that does just that. The script monitors each collapsible section and checks whether all visible fields within that section have been filled out. If they are, the section is marked as “complete” with a visual indicator.

Now, a quick note: this isn’t performing any advanced form validation — it’s not checking for correct formats or required fields. It simply looks for whether each visible field in the section has a value. Once they do, the section gets flagged as completed.

It’s a simple, user-friendly way to help guide users through long forms by giving them a sense of progress as they go.

See more examples in this tutorial

Add the tracking JavaScript

Add the below JavaScript to your form using the Code Chest plugin. This JavaScript code snippet does all the heavy lifting we’ll need. So just copy and paste it over to your form code chest and you’re good to go!

const CS_CHECK_ONLY_REQUIRED_FIELDS = true;

const checkCollapsibleSectionComplete = (sectionBody) => {
	const sectionComplete = ( sectionBody.querySelectorAll('.-cs-field-check').length === sectionBody.querySelectorAll('.-cs-field-completed').length );
	document.getElementById( sectionBody.getAttribute('aria-labelledby') ).classList.toggle('-cs-completed', sectionComplete);
};

const toggleCollapsibleSectionFieldCompleted = (input, completed) => {
	input.closest('.gfield').classList.toggle('-cs-field-completed', completed);
	checkCollapsibleSectionComplete( input.closest('.collapsible-sections-collapsible-body') );
};

gform.addAction('gf_collapsible_sections_setup', (form_id, current_page, formDomId) => {
	
	const csFormWrap = document.querySelector(`#gform_wrapper_${formDomId}`);
	const csFieldsSelector = CS_CHECK_ONLY_REQUIRED_FIELDS ? '.gfield.gfield_contains_required' : '.gfield';
	csFormWrap.querySelectorAll(`.collapsible-sections-collapsible-body ${csFieldsSelector}:not(.gfield--type-hidden):not(.gfield--type-html):not(.gfield--type-section)`).forEach(field => {
		field.classList.add('-cs-field-check');
	});

	// text based inputs
	csFormWrap.querySelectorAll(`.-cs-field-check textarea, .-cs-field-check input:not([type="checkbox"]:not([type="radio"]:not([type="hidden"])`).forEach(input => {
		['change', 'keyup', 'blur'].forEach(eventName => {
			input.addEventListener(eventName, (e) => {
				const fieldCompleted = ( e.currentTarget.value !== '' );
				toggleCollapsibleSectionFieldCompleted( e.currentTarget, fieldCompleted );
			});
			input.dispatchEvent(new Event(eventName));
		});
	});

	// radio / checkbox based inputs
	csFormWrap.querySelectorAll(`.-cs-field-check input[type="radio"], .-cs-field-check input[type="checkbox"]`).forEach(input => {
		input.addEventListener('change', (e) => {
			const fieldCompleted = ( e.currentTarget.checked || e.currentTarget.closest('.ginput_container').querySelectorAll('input:checked').length );
			toggleCollapsibleSectionFieldCompleted( e.currentTarget, fieldCompleted );
		});
		input.dispatchEvent(new Event('change'));
	});
	
	// selects
	csFormWrap.querySelectorAll(`.-cs-field-check select`).forEach(select => {
		select.addEventListener('change', (e) => {
			const fieldCompleted = ( e.currentTarget.value !== '' );
			toggleCollapsibleSectionFieldCompleted( e.currentTarget, fieldCompleted );
		});
		select.dispatchEvent(new Event('change'));
	});
	
	// signature field input
	csFormWrap.querySelectorAll(`.-cs-field-check.gfield--type-signature input[name$="_data"]`).forEach(input => {
		input.addEventListener('change', (e) => {
			const fieldCompleted = ( e.currentTarget.value !== '' );
			toggleCollapsibleSectionFieldCompleted( e.currentTarget, fieldCompleted );
		});
		input.lastValue = input.value;
		clearInterval(input.pollChanges);
		input.pollChanges = setInterval(() => {
			if ( input.value !== input.lastValue ) {
				input.lastValue = input.value;
				input.dispatchEvent(new Event('change'));
			}
		}, 200);
		input.dispatchEvent(new Event('change'));
	});

});

Add the CSS

Once you’ve added the JavaScript tracking snippet from above, add one of the example CSS snippets to get the style and checkmark layout that works for you. See the examples below and corresponding CSS snippets to copy and paste.

This CSS design example positions the complete check mark inline to the left of the section title. Makes for an easy and clean way to tell what a user has completed. Updated the colours below to customise it even further. Fill out some details in the demo below to see it in action.

.collapsible-sections-field.-cs-completed:not(.collapsible-sections-section-error):before {
    content: "✓";
    width: 20px;
    height: 20px;
    overflow: hidden;
    position: absolute;
    left: 20px;
    top: 50%;
    background-color: #2cc9b6;
    color: white;
    border-radius: 100px;
    line-height: 20px;
    font-size: 16px;
    text-align: center;
    transform: translateY(-50%);
    padding: 16px;
    display: flex;
    justify-content: center;
    align-items: center;
}

[class*=cs-theme--] .gsection.collapsible-sections-field.-cs-completed:not(.collapsible-sections-section-error) {
    --cs-background-color: #e1fdf9;
    --cs-border-color: #00b295;
    padding-left: 70px !important;
}