FormBuilder: HTML forms made simple
Even though HTML forms tend to be much of a muchness, each is different enough to require customized markup, styling, and validation. Sometimes it feels like reinventing the wheel. Over the past year I have been progressively streamlining the way I build my forms, and recently got to a point where I realized it wouldn’t take much more work to create an all-in-one PHP class that generates form markup, validates input, and displays error messages to the user. So that’s what I did, and I’m sharing it here in the hope someone else finds it useful too.
FormBuilder features
FormBuilder is designed to do make building forms simple. It can do pretty much everything you might want to achieve with a typical HTML form:
- Create HTML forms by entering a few PHP values
- Generates XHTML 1.0 Strict compliant markup
- Fully skinnable via CSS
- Rigorous and flexible form validation on a per-field basis
- Displays easy to understand error messages to the user
- Highlights required fields and fields that are in error
- Automatically send form results to any email address
- Displays a ‘thanks’ message once form is successfully processed
- Hide or show HTML content based on whether the form was successfully submitted
- Ability to add your own custom form validation after FormBuilder has completed its own validation pass
- Protect against PHP header injection
Demo and download
I put together a demo page that shows FormBuilder in action. Try filling out the form incorrectly to see examples of FormBuilder’s error messaging.
View FormBuilder demo
Demonstrates default FormBuilder setup.
View FormBuilder ‘pretty’ demo
Demonstrates the showDividers and usePseudoLegends options. These make your forms easier to style but less semantic.
Download FormBuilder (current version is v1.4)
Important: FormBuilder is a work in progress, so I can’t promise it’s completely bug free. Feedback, suggestions and bug reports are welcomed: leave a comment below.
How the heck do I use this thing?
You should be able to get a pretty good idea how FormBuilder works just by looking at the source code of index.php in the download package. If you want to dig a little deeper I included a text file with the package that documents all aspects of the class and how to use it. And if you’re still scratching your head feel free to post a comment below.
Requirements
FormBuilder must be run on a web server with PHP 4+ running (I’ve tested under both PHP4 and PHP5). A basic understanding of PHP is helpful, but if you follow the examples provided in the documentation you might be able to make do without. CSS knowledge is required if you want to change the appearance of the form.
AJAX validation
Over at roScripts there is a nice tutorial explaining how to modify FormBuilder so that validation is performed unobtrusively using AJAX.
Changelog
Version 1.4
- Added
emailResultsfunction, which automatically emails the form variables to any email address
Version 1.3
- Added new field type: password
- Added new field type: hidden
Version 1.2
- By default there is no longer an empty
ddafter each form field, which makes FormBuilder’s markup more semantic. The emptydd's provide a handy element for styling visual dividers between fields, so you can still reveal them using the newshowDividersparameter in the FormBuilder constructor. - Introduced
usePseudoLegendsparameter. If set to true,legendwill be replaced withh3. The HTMLlegendelement is notoriously difficult to style consistently, and this parameter provides a workable alternative. - Cleaned up the demo CSS styles, including getting dividers displaying properly in Safari.
Version 1.1
- Checkboxes and radio buttons are now correctly marked up inside label tags
- Labels are now associated with the relevant form field via the
forattribute
Credit where credit is due
FormBuilder uses validaForms by Erick Vavretchek for form validation. Please see the validaForms PHP Classes package if you wish to learn more about this excellent from validator.
Comments
Add a comment
Comments are moderated, so your comment will not appear on the site immediately.
1Arjan Eising
You don’t use the
labelelement properly for your output code. The label element should also be used for the options for checkboxes and radio buttons, and better have thefor-attrubute to point to the form fields. Read the spec for more info on that.2Jonathan
@Arjan – Thanks for the feedback – much appreciated! I have modified my class to output the
forattribute for labels, and checkbox and radio inputs are now also wrapped in label tags. The current demo/download reflect these changes.3Arjan Eising
Cool, it’s much better now. I’ll test this soon for one of my own forms
4Jonathan
@Arjan – Thanks. I’m still struggling with the semantics of it a bit. You probably noticed I’ve gone for a definition list to structure the form elements, largely to make styling the form as flexible as possible. Which I’m OK with, but it makes it awkward to add a visual divider between the form label/input pairs. Hence the additional ‘divider’
<dd>, which is there purely for decorative effect. It validates, but having an empty<dd>I’m pretty sure isn’t semantic! I could always just drop the dividers of course, but on a purely visual level my preference is to have some sort of visual separation between each form element. Can you tell I’m more of a designer than a developer5Shani elharrar
Well, i think you should replace the divider with horizontal rule
“Definition and Usage
The tag inserts a horizontal rule.” (http://www.w3schools.com/tags/tag_hr.asp)
Keep up the good work.
6Jonathan
@Shani – The only legal elements inside a definition list are
<dt>and<dd>. Thanks anyway.7Jermayn Parker
Cool, will bookmark it and use it for my current project which uses a few forms..
8Aaron Bassett
Rather than add an empty dd could you not apply a border-bottom using CSS to each dd to provide the required separation between fields?
9Jonathan
@Aaron – it couldn’t span the full width of the form (assuming the form is layed out in pseudo columns). If the form is layed out vertically, with the field labels (ie: the dt’s) above the dd’s then your suggestion would work.
I think a more workable solution is probably to use an ordered list instead of a definition list. Or to do away with the list altogether, float the labels left, and use a div as the divider to clear the floats. When I have some time I’ll look into both of these possibilities.
10Jonathan Schultz
Great efforts, BUT PEAR have HTML_form which is about 200 times more advanced and has skin able code. There code is pretty bulky so I built my own so you have done well also, I still feel that your code is pretty ridged though. I might package my code up and attach a link here. It might help who knows.
Thanks
Jonathan
11Jonathan
@Jonathan Schultz – Sure, I’d love to see what you have done. I’m more of a designer than a developer, so I have no doubt my PHP is shakier than it could be.
12Jonathan
By the way, I recently launched a client site where I used my class for all of the forms. In the mailing list section I have two forms on one page which seems to work nicely too.
13Marjan
I think I’m blind. First of all, great script. And for the blindness: where do you write an email?
Take care!
14Jonathan
@Marjan – Sorry, I’m not sure I understand your question. What do you mean “where do you write an email”? If you are referring to the form handling (ie: sending the processed form variables to an email address), you’ll need to code this up yourself. In my demo index.php file you will see where I write the variables to screen upon successful form submission – this is where you would format and send your email. If you’re not sure how to do this, see the PHP mail function.
15Jonathan
I have updated my class so that the markup generated by FormBuilder is more semantic. You can read about the new changes above, under the heading “What’s new”.
16David
Hi
Great form, does this send an email with the users details of what they have entered to s specified email address?
17Jonathan
@David – No, it doesn’t. I’ve left it up to the developer to decide what they want to do with the form variables once they are processed. But since sending the variables in an email is a very common use for a web form I think in the next version I will add this option, which will make the form more user friendly for non-programmers. See comment #14 above for a description of how you would currently go about sending the variables in an email.
18Michael McCorry
Hi Jonathan,
First of all, great script. It’s already come in very handy for me. I’ve had to make a few alterations to the script, but I thought they were needed and that you might like to include them in any upcoming new version.
First I added support for “password” and “file” field types. Then I added “hidden” fields. Finally I added a custom “content” field, for spots when i don’t necessarily want a form field to appear but a set static bit of content.
Great work again, and thanks.
19Jonathan
@Michael McCorry – I’m pleased to hear you have found the script useful! I have password and file field types on my to-do list, but hadn’t considered hidden fields which is a great suggestion. I’ll roll all of these into my next update. If you don’t mind sharing your code, you could save me some time by sending your revised version to me at jonathan at f6design dot com. Cheers.
20Jonathan
I have updated FormBuilder to support password and hidden field types.
21Jonathan
Another update to the FormBuilder class. Version 1.4 features a new function emailResults, which can be used to automatically send the user-submitted form variables to any email address. It should be clear from the demo files and the FormBuilder documentation how this works, but if anyone is unsure please let me know.
22Erick Vavretchek
That’s a good work!
Thanks for the credits about validaForms class.
Cheers,
Erick
23Jeff Owens
Awesome script. I’m planning to use it on my own site and on my customers’ as well!
I’d like to be able to set a default value for a form element based upon certain criteria. I know how to get a variable set with the value I want, but my lack of understanding of either PHP arrays or else FormBuilder itself are causing my form not to work.
Here’s what I’m trying to do within a $contactForm->addField call:
‘defaultvalue’ => $default_subject
$default_subject is set to a string, such as “General Inquiry”. What happens is that I get a parse error, as follows:
Parse error: parse error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting ‘)’
Any ideas on a way around this?
24Jonathan
@Jeff – The most likely reason is that you missed a comma after one of the objects in your addField array, as in:
‘radiovalues’ => array(‘y’,'n’)
‘defaultvalue’ => ‘n’
instead of:
‘radiovalues’ => array(‘y’,'n’),
‘defaultvalue’ => ‘n’
Also, I’m not sure how you plan on using the defaultvalue variable, but bear in mind it
only applies to the ‘radio’ field type(edit: applies to ’select’ too). Checkboxes use ‘checkboxchecked’ to achieve the same thing. For other field types… to be honest it wasn’t something that had occurred to me! It’s a good suggestion though.25Jeff Owens
Ah, I guess I didn’t realize “defaultvalue” didn’t work with the select tags. The idea was that depending on what part of the website the customer reached the form from, the “Subject” for the form would be filled in with a default value in the select drop-down list.
Oh, and the problem was a missing comma. Doh!
I’ll have to figure out some other way around filling in the default subject, I guess.
26Jonathan
My bad – it does actually work with ’select’ too – but I realise my documentation for the class doesn’t mention select at all. Duh. I’ll update the docs when I have a sec. I can see how it could be useful to have defaultvalue work for regular textfields too, so I’ll include that in my next update as well.
27Jeff Owens
I figured that out after my last comment. Everything is working now on my end. Thanks again for the great script!
28Joe
First of all: You Beauty! This is fantastic, kudos to you and everyone else who has contributed to formBuilder.
Secondly, a question: I’m testing formBuilder on a “subscribe to mailing list” form. My problem is that the form data is normally sent to a third-party newsletter management web app using … My php skills are weak and am unsure how to pass the data from the form to some.url once the form has been successfully completed.
Any help would be appreciated. Keep up the good work!
29Joe
using… form action to some.url and method post
30Jonathan
Joe – Sorry, but FormBuilder won’t do what you want. To perform its validation routine, FormBuilder’s POST URL must be the same as the page that the form is on. If you want a form that integrates with a 3rd party newsletter app then any validation will occur on their server (at least that’s been my experience), so all you need at your end is a basic HTML form – they should be able to provide you with the markup for a sample form.
31Joe
Ok, fair enough… I’ll have to stick to the old script then, but I will be using formBuilder for the other forms. Thanks for sharing (and the prompt reply)!
32Milton
Does your form store the values in variables a need a form that does that
33Jonathan
@Milton – After submitting the form, variables are accessible in the usual PHP manner: $_POST['fieldname']. If you look at the demo scripts included in the download you will see an example for accessing submitted variables.
34Al
Congratulations. Finally found a nice and efficient script. Cheers!
35Jonas
This is wonderful! Many thanks for sharing this work. There are three things I need to add to make this the single best form validation class I’ve seen.
1) Ajax support – saw the roScripts tutorial, but prefer jQuery and it looked a little rough.
2) Additional header/instructional text options. Sometimes you need extra text and markup to explain different sections, etc. Currently you can only do it with fieldsets/h3’s but it would be nice to have, say, an h4 or p option, too.
3) Some way to integrate reCaptcha – has anyone done this? It shouldn’t be too difficult, probably just a couple more functions need to be added to the class. I’ll take a whack at that one and see if I can get it to work.
36Scott
Absolutely brilliant.
This is going to save me so much time!
Great work. Thanks!
37Jonathan
@Jonas
1) I may look into it…
2) I take it you would like to have a fieldset heading, then underneath it some further instructions? I can see how this could be useful.
3) Will be included in my next FormBuilder update.
38Rick
I really like this script, great work! One problem I have though is the confirmation page – because it’s not easily tracked .. clients want to track successful form submissions in google analytics for example – this needs to be a seperate URL.
Could there be a option to allow a redirect? Obviously the header would have to come before the form is included and it could end up being more of a pain for less experienced php’er’s (I’m by no means expert).. I can see why you haven’t bothered.
BTW, I like the idea of having a Captcha.
39Gianfranco
Thanks for the great script Jonathan! I have been playing around with it, but it appears that the checkbox code has a slight bug. In line 122 of FormBuilder.php you are checking whether the current checkbox field is set to required and only then do you process it. If the field is not set to required its contents are ignored. I fixed it with some probably inefficient code, perhaps you can have a look at it and fix it in a somewhat nicer way.
40Jonathan
@Gianfranco Thanks for noticing this glitch! I’ve been meaning for a while to do an update to FormBuilder, so I’ll add this to the list…
41Alexander
Hello, thank you for this script.
Could you make an internalization feature for your future releases? I mean possibility to translate strings of messages and errors. Maybe simple txt files – one for each language.
42Alexander
And one more thing: I see that your script didn’t escape submitted values (for textbox for example). I think you should apply htmlspecialchars() to post values before render form.
43Jonathan
@Alexander – The escaped caharacters occur on system where PHP’s magic quotes are turned on. Magic quotres has been deprecated, but I will make an allowance for it in the next upgrade.
44Fawad Awan
Thanks for the nice resource.
45Dennis Kim
FormBuilder is perfect for my freelance projects, thanks for putting in the time and effort to create it.
I have a suggestion for you to consider: when appending the required asterisk, it would be nice if it were appended with a non-breaking space entity to prevent widowing the * on labels that wrap.
46Josh
Great script,It’s helps me out alot. Just had one question does it allow for file uploads?
47Joe
Jonathan,
thanks a lot for this class. It works great for me.
One tip for guys with a need for utf-8 encoding in the mails:
Just add ‘ . “Content-Type: text/plain; charset=utf-8″); ‘ in the emailResults-function approximately on line 385 (approximately because i made some more changes and maybe added some lines above therefore).
It should look like this then:
mail($recipientEmail,$subject,$emailBody,$headers . “Content-Type: text/plain; charset=utf-8″);
Best
Joe
48Phil
Is is possible to add another validationtype for text fields, where the field has to be equal to x… so that a rudimentary captcha can be added… eg. “Please type the value 3+4″ … so the user has to input the number 7.
49Jonathan
@Phil – I actually have plans to add CAPTCHA to FormBuilder, but you could also achieve what you want by adding your own custom validation, something like this:
if($contactForm->isSubmitted()){
if ($_POST['captcha'] != ‘7′){
$contactForm->forceErrorMessage(‘captcha’,'Your error message here’);
}
}
Have a look at the source of my demo and you’ll see an example of the isSubmitted method.
50Phil
Thank you for your reply, I’ll give that a go… reCaptcha might be a good service to consider – http://recaptcha.net
51Tobias
Hi, i found it difficult to adjust the form. Example:
I have these 2 related fields: postalcode and city. Here in the Netherlands PC is only 6chars, so i fully width field would be stupid. Therefore I would like to combine PC and City at one height. But of course, keep the input fields seperated.
PC + City [input filed] __ [longer input field]
Because all dd’s and dt’s are styled the sameway I wonder if it’s possible at all… Please contact me, your formbuilder rocks ass! really
52Jonathan
@Tobias – I can’t immediately think of a way to achieve what you want. You should be able to style individual fields via CSS, since each field has an id – for instance you could make the postcode field shorter. But targeting field labels would be trickier. If you used javascript (maybe jquery) you might be able to attach CSS classes to specific label, dd or dt elements and wrestle more control over the way they are styled.
53Tobias
@Jonathan: Well that might be one way, but I found it not worth the effort. the script is nice if you need what it does, so I still use it now and then but for more “complicated” forms, i’ll stick to my own forms.
54Jonathan
@Tobias – Agreed! There’s a limit to how flexible my script is, and for complex form layouts you are better off rolling your own.
55Gnik Nalu
Is there a way to pass a default value into the text forms from a variable? For example:
$contactForm->addField(array (
‘id’ => ‘guess_city’,
‘type’ => ‘textbox’,
‘label’ => ‘The City You Are In’,
‘required’ => false,
‘maxlength’ => 2,
‘defaultvalue’ => $guess_city,
‘headerinjectioncheck’ => ‘full’
));
‘defaultvalue’ will be the text between the or in the value= so the form will have pre-filled in data.
Thx for formbuilder – it is TOTALLY AWESOME
56Gnik Nalu
seems it removed html.
Let me restate a portion of what was above:
‘defaultvalue’ will be the text between the elements or in the value= so the form will have pre-filled in data.
57Gnik Nalu
Peeking @ the code I see a $field['defaultvalue'] mentioned. is this something that can be used to put in a ‘default value’ in a form? (Just being nosey.)