
🕵️ How to hide the submit button in Contact Form 7 until fields are filled: 3 working methods
A user opens a form, sees a "Submit" button, clicks it, and gets validation errors. The window highlights fields in red: "Required." Sound familiar?
Contact Form 7, the most popular forms plugin for WordPress, has 5+ million active installations. But out of the box it always shows the submit button, even when fields are empty. For the user this means an extra click and frustration. For the site owner it means lost leads: a third of visitors who encounter a form error simply leave and never return.
You can fix this with three lines of jQuery. Or you can do it without any scripts at all, using pure CSS. In this breakdown you get both approaches, plus a ready-made plugin for those who do not want to touch code.
💡 Quick overview:
- jQuery tracking: hide the button and show it only when the text length in all fields reaches your limits
- Pure CSS: a trick with
:valid,:has()and therequiredattribute, without a single line of JavaScript - Conditional Fields for Contact Form 7 plugin: a visual conditions builder for complex logic without code
Why hide the submit button
A user should not have to guess what went wrong. When a button is visible and clickable but the form is not ready, it creates cognitive dissonance. The person clicks, gets an error, scans for highlighted fields, fixes them, clicks again. Every such cycle lowers conversion.
A button hidden until everything is ready solves three problems:
- Eliminates false submission attempts. No button, no premature click.
- Provides visual feedback. The button appearing = a signal that the form is ready to submit.
- Reduces friction. The user fills in the fields, the button appears, one click, done.
Contact Form 7 has no built-in mechanism for this behavior. But adding it takes 10 minutes of work.
Method 1: jQuery input tracking
The most flexible approach. You set your own rules: how many characters each field must contain before the button appears. Works with any field type (text, email, textarea, phone).
Contact Form 7 form body
As an example, take a standard contact form with three fields, Google reCAPTCHA, and a submit button. Here is its markup in the CF7 editor:
1 [text text-776 id:bim-name class:bim-name placeholder "Name"] 2 [email email-498 id:bim-email class:bim-email placeholder "Email"] 3 [textarea textarea-697 id:bim-message class:bim-message placeholder "Message"] 4 5 <style> 6 .g-recaptcha > div { 7 width: 100% !important; 8 } 9 .g-recaptcha iframe { 10 width: 100% !important; 11 } 12 div#GoogleReCapchaFullWidth { 13 width: 100% !important; 14 padding-bottom: 6px; 15 } 16 </style> 17 18 [recaptcha id:GoogleReCapchaFullWidth] 19 20 [submit id:bim-button class:bim-button "Submit"]
The CSS block inside the form is a workaround for stretching reCAPTCHA to full container width; it comes in handy if the form sits in a narrow column.
jQuery script
Copy this code into your theme's custom.js file or into the "Additional Scripts" field of the Code Snippets plugin:
1 jQuery(document).ready(function ($) { 2 3 // Initially the button is hidden 4 $('#bim-button').css('display', 'none'); 5 6 // Listen for input on all three fields 7 $('#bim-name, input#bim-email, #bim-message').on('input', function () { 8 var nameVal = $('#bim-name').val().trim(); 9 var emailVal = $('#bim-email').val().trim(); 10 var messageVal = $('#bim-message').val().trim(); 11 12 // Conditions: name > 4 characters, email > 6, message > 20 13 if (nameVal.length > 4 && emailVal.length > 6 && messageVal.length > 20) { 14 $('#bim-button').fadeIn(200); 15 } else { 16 $('#bim-button').fadeOut(200); 17 } 18 }); 19 20 });
What is happening here:
- Line 4: the button is hidden immediately on page load (
display: none). - Line 7: the
.on('input', ...)method listens for any text change in the three fields (the user typing, pasting from clipboard, deleting characters). Previously.keyup()was used, butinputis more reliable: it also fires on mouse paste. - Lines 8-10: we read current values and trim whitespace from the edges via
.trim(). - Line 13: condition check. You can change the numbers to suit your needs: for instance,
> 1may be enough for a name field,> 10for a message. - Lines 14 and 16:
fadeInandfadeOutgive a smooth appearance and disappearance of the button over 200 milliseconds. It looks tidier than an abruptshow()/hide().
Physically the button element is always in the page's DOM tree; visibility is controlled by the CSS display property. This is safe: even if the script fails to load (network issue, ad blocker), the button simply stays visible and the user does not lose the ability to submit the form.
How to adapt for your form
Change three things:
- Field IDs: in the CF7 markup replace
bim-name,bim-email, andbim-messagewith your own identifiers. - Character limits: in the
ifcondition insert the numbers you need. For a phone field you can check.replace(/\D/g, '').length > 9(digits only, at least 10). - Field list: if you have 5 fields, add them to the selector
$('#id1, #id2, ...')and to theifcondition.
For [checkbox], [select], or [radio] field types, text length does not work; check the selection itself:
1 var agreeChecked = $('#bim-agree').is(':checked');
Method 2: pure CSS without scripts
For simple forms with one or two fields you can skip JavaScript entirely. The idea is that modern browsers can check field validity via the :valid pseudo-class, and the CSS combinator :has() (supported in all browsers since 2023) lets you look "inside" a parent element.
It works like this:
1 form.wpcf7-form .wpcf7-submit { 2 display: none; 3 } 4 5 form.wpcf7-form:has(input[required]:invalid) .wpcf7-submit { 6 display: none; 7 } 8 9 form.wpcf7-form:not(:has(input[required]:invalid)) .wpcf7-submit { 10 display: block; 11 }
But there is a nuance: CF7 does not add the required attribute to fields automatically. You need to add it manually in the form markup; an asterisk * next to the field name in the CF7 editor is enough:
1 [text* text-776 id:bim-name placeholder "Name"] 2 [email* email-498 id:bim-email placeholder "Email"]
The asterisk after the field type (text*, email*) enables mandatory status. CF7 itself will insert the HTML required attribute into the <input> tag, and the CSS selector will work.
The upside of the CSS method: zero scripts, it does not break on jQuery conflicts, and it works even with JavaScript disabled. The downside: the logic is simpler ("all required fields are filled" versus "the name field is longer than 4 characters"). For most contact forms this is sufficient.
Method 3: Conditional Fields for Contact Form 7 plugin
When the logic gets more complex (for example, show the button only if a specific item in [select] is chosen and the email is filled), jQuery code grows. This is where the free plugin Conditional Fields for Contact Form 7 comes to the rescue (100,000+ active installations, 5-star rating).
The plugin adds a visual conditions editor right inside the CF7 interface. You set rules in a couple of clicks:
- "Show the button if the 'Name' field is not empty AND the 'Email' field is not empty AND the 'Message' field contains more than 20 characters."
- Or: "Show the 'Delivery address' field if the 'Courier delivery' radio button is selected."
No code required. Conditions can be applied to any field or group of fields, including the submit button itself. The plugin is actively maintained and regularly updated; as of June 2026 it is compatible with the current WordPress version.
Which solution to choose
Three approaches cover three different scenarios:
- Pure CSS: ideal for a landing page with a simple 2-3 field form. Minimum moving parts, nothing to break.
- jQuery script: your choice when you need fine-tuned limits ("name longer than 4 characters, message longer than 20"). Full control over conditions.
- Conditional Fields: use it when the logic branches (different sets of fields for different choices, nested conditions, showing/hiding entire form sections). The visual builder saves hours of debugging.
For most WordPress sites the combination of "jQuery + common sense" is enough. The script above (20 lines) is inserted once and works for years without updates.
Video: step-by-step setup
This 8-minute tutorial walks through the entire process, from creating a form in CF7 to a finished button-hiding script that checks whether all fields are filled:
⁉️🤔 Frequently asked questions
Does the script work with caching plugins?
Yes, provided the proper
jQuery(document).ready(...)wrapper is used. If the site employs aggressive minification (Autoptimize, WP Rocket with script combining), exclude the script file from combining or use the Code Snippets plugin: it inserts code into the page footer as a separate block that minifiers do not touch.
What if a user has JavaScript disabled?
With JavaScript disabled the button stays visible; the script simply does not hide it. This is graceful degradation: CF7 will perform server-side validation and display errors the standard way. For the CSS method using
:has()the situation is the same: without JS validation CF7 still checks fields on the server upon submission.
Can I hide the button for a specific form if there are several on the page?
The easiest way is to give the button a unique
idin the CF7 editor, then use that ID as the selector in the script. If there are multiple forms, duplicate the code block for each button with its own ID, or dynamically find the button inside the current form via$(this).closest('form').find('.wpcf7-submit').
Why not just use required on fields and rely on browser validation?
Because
requireddoes not hide the button; it only blocks form submission and shows a browser-native tooltip. Our goal is to remove the very opportunity for an erroneous click. Additionally, standard browser validation does not check text length, only the fact of filling, and for a message that is 2 characters long this is weak protection.
Do I still need to validate fields on the server?
Yes, absolutely. Client-side logic for hiding the button does not replace CF7 server-side validation. Always configure required fields in the form editor (the
*in the markup) and verify that emails are delivered. Two layers of protection: frontend for convenience, backend for security.
Hidden button, clean leads: what to use on your site
The approach of hiding the submit button is one of those micro-improvements that are invisible to the eye but noticeable to the hands. A user will not say "awesome, the button appeared at the right moment." But they will complete the form and not leave after the first click into the void.
For a simple contact form, use the CSS method with :has(): 5 lines of code, zero dependencies. For custom length limits on fields, use the jQuery script from method 1 (copy and paste into Code Snippets). For complex forms with branching logic, use Conditional Fields.
Try it right now: open your contact form editor in CF7, add id: to fields and the button, paste the script, and check how the button appears only when all fields are filled meaningfully, not haphazardly.



