FormBuilder: HTML forms made simple

Important: I no longer maintain FormBuilder. If you need a standalone PHP form builder I recommend Swiftmailer.

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

Download FormBuilder (current version is v1.5)

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.


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.


Version 1.5

  • Better handling of checkbox results in the emailResults method.
  • A custom form submit URL can be passed to the FormBuilder constructor. Useful when using FormBuilder in an environment that is performing URL rewriting.
  • Replaced deprecated ergei functions with preg_match.
  • Checkbox field types are correctly processed when field is not mandatory, and the user didn’t check any of the available options.
  • Added new field type: file (for file uploads). Note that files are currently not emailed when using the emailResults method. Any handling of the uploaded files should be accomplished manually by accessing PHP’s $_Files array.
  • The textbox and textarea field types now accept an optional defaultvalue parameter.
  • Fixed a bug that meant checkboxes had a CSS class of ‘fbheckbox’ instead of ‘fbcheckbox’.

Version 1.4

  • Added emailResults function, 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 dd after each form field, which makes FormBuilder’s markup more semantic. The empty dd's provide a handy element for styling visual dividers between fields, so you can still reveal them using the new showDividers parameter in the FormBuilder constructor.
  • Introduced usePseudoLegends parameter. If set to true, legend will be replaced with h3. The HTML legend element 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 for attribute

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.

64 thoughts on “FormBuilder: HTML forms made simple

  1. Arjan Eising says:

    You don’t use the label element properly for your output code. The label element should also be used for the options for checkboxes and radio buttons, and better have the for-attrubute to point to the form fields. Read the spec for more info on that.

  2. Jonathan says:

    @Arjan – Thanks for the feedback – much appreciated! I have modified my class to output the for attribute for labels, and checkbox and radio inputs are now also wrapped in label tags. The current demo/download reflect these changes.

  3. Arjan Eising says:

    Cool, it’s much better now. I’ll test this soon for one of my own forms ;)

  4. Jonathan says:

    @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 developer ;)

  5. Well, i think you should replace the divider with horizontal rule

    “Definition and Usage
    The tag inserts a horizontal rule.” (

    Keep up the good work.

  6. Jonathan says:

    @Shani – The only legal elements inside a definition list are <dt> and <dd>. Thanks anyway.

  7. Cool, will bookmark it and use it for my current project which uses a few forms..

  8. 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?

  9. Jonathan says:

    @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.

  10. 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.


  11. Jonathan says:

    @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.

  12. Jonathan says:

    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.

  13. Marjan says:

    I think I’m blind. First of all, great script. And for the blindness: where do you write an email? :)

    Take care!

  14. Jonathan says:

    @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.

  15. Jonathan says:

    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”.

  16. David says:


    Great form, does this send an email with the users details of what they have entered to s specified email address?

  17. Jonathan says:

    @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.

  18. 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.

  19. Jonathan says:

    @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.

  20. Jonathan says:

    I have updated FormBuilder to support password and hidden field types.

  21. Jonathan says:

    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.

  22. Erick Vavretchek says:

    That’s a good work!
    Thanks for the credits about validaForms class.

  23. Jeff Owens says:

    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?

  24. Jonathan says:

    @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.

  25. Jeff Owens says:

    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.

  26. Jonathan says:

    Ah, I guess I didn’t realize “defaultvalue”didn’t work with the select tags.

    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.

  27. Jeff Owens says:

    I figured that out after my last comment. Everything is working now on my end. Thanks again for the great script!

  28. Joe says:

    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!

  29. Joe says:

    using… form action to some.url and method post

  30. Jonathan says:

    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.

  31. Joe says:

    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)!

  32. Milton says:

    Does your form store the values in variables a need a form that does that

  33. Jonathan says:

    @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.

  34. Al says:

    Congratulations. Finally found a nice and efficient script. Cheers!

  35. Jonas says:

    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.

  36. Scott says:

    Absolutely brilliant.

    This is going to save me so much time!

    Great work. Thanks!

  37. Jonathan says:


    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.

  38. Rick says:

    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.

  39. Gianfranco says:

    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.

  40. Jonathan says:

    @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…

  41. Alexander says:

    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.

  42. Alexander says:

    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.

  43. Jonathan says:

    @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.

  44. Fawad Awan says:

    Thanks for the nice resource.

  45. Dennis Kim says:

    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.

  46. Josh says:

    Great script,It’s helps me out alot. Just had one question does it allow for file uploads?

  47. Joe says:


    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”);


  48. Phil says:

    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.

  49. Jonathan says:

    @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 ($_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.

  50. Phil says:

    Thank you for your reply, I’ll give that a go… reCaptcha might be a good service to consider –

  51. Tobias says:

    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 :D

  52. Jonathan says:

    @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.

  53. Tobias says:

    @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. :)

  54. Jonathan says:

    @Tobias – Agreed! There’s a limit to how flexible my script is, and for complex form layouts you are better off rolling your own.

  55. Gnik Nalu says:

    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

  56. Gnik Nalu says:

    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.

  57. Gnik Nalu says:

    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.)

  58. Al says:

    hi, may I know who to upload an image by using FormBuilder?

  59. Jonathan says:

    @Al – I’m afraid that isn’t currently possible.

  60. Tim says:

    Thanks Jonathan! I find Form Builder easy to use and to style – thanks for making it available to us, and thanks for the 1.5 version update. Much appreciated! =)

  61. Dimon says:

    Hi everyone!

    How i can add, in this example?

    Thank You for any help!

  62. dan says:

    great tutorial…one question though when the form is submited it does not show the email From: in the header it just says “senders name”. Is there a way to show the senders email ? thanks

  63. Jonathan says:

    @dan You need to populate the emailResults function parameters with values submitted in your form, e.g.

    ‘Email subject’,
    ‘The following is an email sent by a visitor to’

  64. dan says:

    ‘’, // The recipient (ie: you). Should ALWAYS be hard coded.

    how can I change this so that the senders email shows up in the “From” field
    to: Don

Comments are closed.