Forms

How to Build Forms on NYC.gov

Forms on NYC.gov must be both accessible and responsive. Learn about creating accessible forms. Before creating a new form, pull together the content and create the form as follows.

Form Content:

  • In a Word document, compile the form content.
  • Include all fields needed. Note where text input fields, radio buttons, check boxes and drop-down menus are needed.
  • Mark required fields with an asterisk.
  • Include the email address(es) that the form should route to upon submission.
  • Subject of the form

Error Messages for Required Fields

Build, Test, and Publish

  • Submit the content document and error message spreadsheet to your production team with your form request. Or, send them to our webmail team, if you would like us to build your form.
  • Create the form based on the specs below.
  • Ensure the our webmail team has registered the form with the email address and subject before testing.
  • Perform quality assurance (Q/A) on the form to ensure that it meets the style and requirements specified here and in the standards. Test it to ensure that the submission routes properly; that its responsive and accessible; and that the error messages are unique to each required field, and styled properly (e.g., first sentence, which identifies the error in bold and the second sentence, which describes how to fix it not bold).

NOTE: Captcha will be included on all forms that do not require the ability to upload attachments.

The examples below illustrate how to use the NYC.gov framework to build a form on NYC.gov. HTML 5 standards are used, and we recommend that you adhere as close as possible to the standards when building out individual inputs, fields, selects, radio buttons, and checkboxes. These examples are following the standards set by WCAG 2.1 Level AA.

Basic Form Setup

NYC.gov can be set up to handle different data captures. The first type of form - the "regular form" is used for collecting text data. The second type of form - the "form with upload capability". It is used for collecting data and uploading files. Each form type setup is described below.

General NYC.gov Form Setup - Regular Form

HTML Form Element - Regular Form
<form class="control-form" action="https://apps.nyc.gov/nyc-mailform/validation" name="formName" method="post" id="formId" type="external"> 
<input type="hidden" value="Subject" name="subject" /> 
<input type="hidden" value="dropdown, textfield, inline checkbox, inline radio, checkboxes, radios, date, textarea, file" name="required" id="required" /> 
<input type="hidden" value="REMOTE_HOST,HTTP_ADDR,HTTP_USER_AGENT" name="env_report" />
<input type="hidden" value="3" name="g-recaptcha-version" /> 

	...

</form>

All NYC.gov HTML forms start with <form> and must have class="control-form" to inherit the latest styling for the form. The form tags also have several attributes, which are described in the table below.

Form Tag Attributes
Attribute Value Description
action https://apps.nyc.gov/nyc-mailform/validation This processes the form data after the user submits the form.
name formName Change this value to reflect the name of what the form is about.
id formId This is the form unique ID. Change as needed to ensure the ID is unique to the page.
method post The method specifies how to send the form data. This is sent to the page specified in the action attribute. The method will always be "POST".
type external This is a TeamSite-related attribute, used only by TeamSite. Not declaring this will cause the form to not work.

Following the <form>, there are input fields that contain the hidden attribute. These input fields are mandatory and provides the subject, required fields, and browser information that is collected to process the form routing.

Hidden Input Tag Attributes for Subject
Attribute Value Description
name subject This value does not change and is needed for routing the form data.
value Subject of the form Change the value to reflect the subject of the form that is registered in Siebel.

 

Hidden Input Tag Attributes for Required
Attribute Value Description
name required This value does not change and is need for routing the form data.
value The value of the name attribute for each input/fields that is required. List each value follow by a comma. (Example: dropdown, textfield, inline checkbox).
id required Unique ID for the input. Do not change.

 

Hidden Input Tag Attributes for User Agent
Attribute Value Description
name env_report This value does not change.
value REMOTE_HOST,HTTP_ADDR,HTTP_USER_AGENT This value does not change as it provides information about browser, page URL address, and the browser.

 

Hidden Input Tag Attributes for Google reCAPTCHA
Attribute Value Description
name g-recaptcha-version This value does not change.
value 3 This value does not change. It is utlized by reCAPTCHA.

NYC.gov File Upload Form Setup – Form with Upload Capability

HTML Form Element - Form with Upload Capability
<form class="control-form" action="https://apps.nyc.gov/nyc-mailform/validation" name="formName" enctype="multipart/form-data" method="post" id="formId" type="external">
<input value="Form Subject" name="subject" type="hidden" />
<input value="Field1,field2,field3" type="hidden" name="required" id="required" />
<input value="REMOTE_HOST,HTTP_ADDR,HTTP_USER_AGENT" name="env_report" type="hidden" />
<input value="#FFFFFF" name="bgcolor" type="hidden" /> <input type="hidden" value="3" name="g-recaptcha-version" />
... </form>

The form setup with upload capability version of the form is used only when files need to be collected with the submissions of the form. The form initial setup is similar to the regular forms, except for a few differences to the input tags and the <form> tags attributes.

Form Tag Attributes
Attribute Value Description
action https://apps.nyc.gov/nyc-mailform/validation This processes the form data after the user submits the form.
name formName Change the value to reflect the name of what the form is about.
id formId This is the form unique ID. Change as needed to ensure the ID is unique to the page.
method post The method specifies how to send the form data. This is sent to the page specified in the action attribute. The method will always be "POST".
enctype multipart/form-data The enctype attribute specifies how the form-data should be encoded when submitting it to the server. This is only used for file upload.
type external This is a TeamSite-related attribute, used only by TeamSite. Not declaring this will cause the form to not work.

The listed input fields are mandatory and provides the subject, required fields, sort order of the fields, and browser information that is collected to process the form routing.

Hidden Input Tag Attributes for Subject
Attribute Value Description
name subject This value does not change and is needed for routing the form data.
value Subject of the form Change the value to reflect the subject of the form that is registered in Siebel.

 

Hidden Input Tag Attributes for Required
Attribute Value Description
name required This value does not change and is need for routing the form data.
value The value of the name attribute for each input/fields that is required. List each value follow by a comma. (Example: dropdown, textfield, inline checkbox).
id required Unique ID for the input. Do not change.

 

Hidden Input Tag Attributes for User Agent
Attribute Value Description
name env_report This value does not change.
value REMOTE_HOST,HTTP_ADDR,HTTP_USER_AGENT This value does not change as it provides information about browser, page URL address, and the browser.

 

 

Hidden Input Tag Attributes for Google reCAPTCHA
Attribute Value Description
name g-recaptcha-version This value does not change.
value 3 This value does not change. It is utlized by reCAPTCHA.

 

Form Controls

Standard form controls like <input>, <select>, <textarea>, inherit the style from the <form> class .control-form and is wrapped with control-group. The <input>, <select> and <textarea> is wrapped in the <label> and have a control-label class that includes the styles for general appearance, focus state, and more.

Sample Text field
<div class="row">
<div class="container">
<div class="span12">
<div class="control-group">
<label class="control-label">Sample Text field
<input type="text" size="40" name="textfield" placeholder="Textfield"/>
</label>
</div>
</div>
</div>
</div>
Sample drop-down
<div class="row"> 
   <div class="container"> 
      <div class="span12"> 
        <div class="control-group"> 
            <label class="control-label">Sample drop-down</span> 
                   <select name="dropdown" > 
                   <option value="" selected disabled hidden>Make a selection</option> 
                   <option value="Lorem">Lorem</option> 
                   <option value="Ipsum">Ipsum</option> 
                   <option value="Dolor">Dolor</option> 
                   <option value="Sit">Sit</option> 
                   <option value="Amet">Amet</option> 
                   </select> 
            </label> 
        </div> 
      </div> 
    </div> 
</div>
      
Sample Text-area
<div class="row">
<div class="container">
<div class="span12">
<div class="control-group">
<label class="control-label">Sample Text-area:
<textarea name="Sample Message"></textarea>
</label>
</div>
</div>
</div>
</div>

Checkboxes and radios

All checkboxes and radios button that are within the <form> with the .control-form class will inherit all styles for general appearance, focus state, and any additional styles.

Sample check box
<div class="row">
<div class="container">
<div class="span12">
<div class="control-group">
<div class="list_elements">
<label class="checkbox inline">
<input name="The quick brown fox jumps over the lazy dog" value="Yes" type="checkbox">
The quick brown fox jumps over the lazy dog</label>
</div>
</div> </div>
</div>
</div>
The quick brown fox jumps over the lazy dog?
Sample radio input
<div class="row">
<div class="container"> <div class="span12">
<div class="control-group">
<fieldset>
<legend>The quick brown fox jumps over the lazy dog?</legend>
<div class="list_elements">
<label class="radio inline">
<input name="confirm" value="yes" type="radio">Yes
</label> </div>
<div class="list_elements">
<label class="radio inline"> <input name="confirm" value="no" type="radio">No </label>
</div>
</fieldset> </div> </div>
</div>
</div>

List / Stacked Vertically Checkbox and Radios

The checkbox example shown above contained one checkbox. However, in most situations you will have several checkboxes. Similar to the radio button example above, the inputs will need to be grouped. This is accomplished using <fieldset> and with an optional <legend>.

List of checkboxes
Sample checkboxes in a group
<div class="row">
<div class="container">
<div class="span12">
<div class="control-group">
<fieldset>
<legend>List of checkboxes</legend>
<div class="list_elements">
<label class="checkbox inline">
<input type="checkbox" value="First checkbox" name="checkboxes" />
First checkbox</label>
</div>
<div class="list_elements">
<label class="checkbox inline">
<input type="checkbox" value="Second checkbox" name="checkboxes" />
Second checkbox</label>
</div>
<div class="list_elements">
<label class="checkbox inline">
<input type="checkbox" value="Third checkbox" name="checkboxes" />
Third checkbox</label>
</div>
<div class="list_elements">
<label class="checkbox inline">
<input type="checkbox" value="Fourth checkbox" name="checkboxes" />
Fourth checkbox</label>
</div>
<div class="list_elements">
<label class="checkbox inline">
<input type="checkbox" value="Fifth checkbox" name="checkboxes" />
Fifth checkbox</label>
</div> <div class="list_elements">
<label class="checkbox inline">
<input type="checkbox" value="Sixth checkbox" name="checkboxes" disabled />
Sixth checkbox</label>
</div>
</fieldset>
</div>
</div>
</div>
</div>
 

Inline checkboxes
Sample checkboxes in a group
    <div class="row">
<div class="container">
<div class="span12">
<fieldset>
<legend>Inline checkboxes</legend>
<div class="inline_elements">
<label class="checkbox inline">
<input type="checkbox" name="inline checkbox" value="First checkbox" />
First checkbox</label>
<label class="checkbox inline">
<input type="checkbox" name="inline checkbox" value="Second checkbox" />
Second checkbox</label>
</div>
</fieldset>
</div>
</div>
</div>

Submit button

There are two types of predefined submit buttons styles.

Submit button
<div class="row">
<div class="container">
<button type="submit" class="btn btn-primary btn-form-submit">Save changes</button>
</div>
</div>

Please carefully review the information that you have entered before hitting the submit button. Please do not submit the same message more than once; doing so may delay processing.

Submit button with disclaimer
<div class="row formControl-row">
<div class="container submit-container">
<p>Please carefully review the information that you have entered before hitting the submit button. Please do not submit the same message more than once; doing so may delay processing.</p>
<button type="submit" class="btn btn-form-submit">Submit</button>
</div>
</div>

Input FileUpload

The file upload object is a customized and styled differently from the default look and feel. This file upload input requires a custom JavaScript library to be included on the page to function.
This is some placeholder block-level help text for the above input. It's a bit lighter and easily wraps to a new line. Aria description will be in this help text.
Input FileUpload
<div class="row">
<div class="container">
<div class="span12">
<div class="control-group">
<label for="file-input" class="control-label">File Input</label>
<input type="file" name="file" id="file" aria-describedby="fileHelp" class="inputfile" />
<label class="fileInput-label btn" for="file"><strong>
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"></path>
</svg>
Choose a file&hellip;</strong><span>no file selected</span> </label>
<small id="fileHelp" class="form-text text-muted">This is some placeholder block-level help text for the above input. It's a bit lighter and easily wraps to a new line.Aria description will be in this help text.</small> </div>
</div>
</div>
</div>

Validation

Feedback to users is recommended and must adhere to WCAG 2.1 Level AA when interacting with a form. Using the browser default validation feedback with HTML5 is supported, however it is recommended to use custom validation styles, as native browse defaults are not entirely announced to screen readers. Below are default styles provided to assist in custom validations.

In the following example, the sample drop-down does not utilize the HTML required attribute, instead requires JavaScript to validate the input fields. To make sure assistive technologies know that these fields are required, we added the aria-required attribute. Please take note of additional aria- tags that is used for assistive technologies. JavaScript also control the values of the aria tags attributed during the validation process.

Sample drop-down with Aria tags when error state is not active
<div class="row"> 
   <div class="container"> 
      <div class="span12"> 
        <div class="control-group"> 
            <label class="control-label">Sample drop-down<span class="required">*</span> 
            <div class="validationMessage" aria-live="polite" style="display: none" aria-hidden="true"></div>
                   <select name="dropdown" aria-required="true" > 
                   <option value="" selected disabled hidden>Make a selection</option> 
                   <option value="Lorem">Lorem</option> 
                   <option value="Ipsum">Ipsum</option> 
                   <option value="Dolor">Dolor</option> 
                   <option value="Sit">Sit</option> 
                   <option value="Amet">Amet</option> 
                   </select> 
            </label> 
        </div> 
      </div> 
    </div> 
</div>
  
Sample drop-down with Aria tags when error state is active
<div class="row"> 
   <div class="container"> 
      <div class="span12"> 
        <div class="control-group"> 
            <label class="control-label validationError">Sample drop-down<span class="required">*
            <div class="validationMessage" aria-live="polite" aria-hidden="false">Validation Error Message <span>The quick brown fox jumps over the lazy dog</span></div>
                   <select name="dropdown" aria-required="true" > 
                   <option value="" selected disabled hidden>Make a selection</option> 
                   <option value="Lorem">Lorem</option> 
                   <option value="Ipsum">Ipsum</option> 
                   <option value="Dolor">Dolor</option> 
                   <option value="Sit">Sit</option> 
                   <option value="Amet">Amet</option> 
                   </select> 
            </label> 
        </div> 
      </div> 
    </div> 
</div>
  

Any required field will need a <div> with class="validationMessage" to display the validation error message. In addition, <label> will need to have the validationError class for the error states to be applied to the input field.

Validation div
<div class="row"> 
   <div class="container"> 
      <div class="span12"> 
        <div class="control-group"> 
            <label class="control-label validationError">Sample drop-down<span class="required">*</span> 
            <div class="validationMessage" aria-live="polite" style="display: none" aria-hidden="true"></div>
                  ...
            </label> 
        </div> 
      </div> 
    </div> 
</div>

JavaScript

When using either of the type of forms processing methods, a custom JavaScript library was developed to handle basic validation for all fields and handle the fileUpload functionality. The basic validation is limited to checking required fields and validation on email address and phone numbers. Following the HTML pattern laid out here will allow the JavaScript to validate required fields listed in the hidden inputs. It is not encourage to use the HTML 5 required attribute since the JavaScript is already performing the action for error reporting.

The following JavaScript asset must be included on the page and is recommended to be place after the form, preferable in the footer:

JavaScript Library File
<script type="text/javascript" src="/assets/home/js/forms/forms-v3.js"></script>

Activating the validation from the custom JavaScript

To use the validation functionality from the JavaScript, the form id is used as a parameter for the submitForm function.

Javascript Library Example for Validation
<form class="control-form" action="https://apps.nyc.gov/nyc-mailform/validation" name="formName" method="post" id="formId" type="external"> 
  ...
 <button type="button" onclick="submitForm('formID');" class="btn btn-form-submit">Submit</button>

Declaring Custom Error Messages

The JavaScript library file that appears on the form has a default validation error message that will populate the <div> with the validation message. However, this acts as a failsafe in case the custom error messages were not defined. From an accessibility standpoint, custom error messages are required for required fields on the forms. Custom error messages must include two parts—the first sentence should note the form element/field label that contains the error, and the second sentence should explain how to fix it.

To add your own custom error messges, you will need to add new elements to the existing array. The existing array name is formCustomErrorMsg which is declaredin the JavaScript library. Start by creating a new JavaScript file to be place directly after the forms-v3.js

Custom Error Message JavaScript Library File
<script type="text/javascript" src="/assets/home/js/forms/forms-v3.js"></script>
<script type="text/javascript" src="/assets/agency-name/js/pages/form-id-custom-errors.js"></script>

Next populate the JavaScript file with the data from the error message template. The following syntax is used to add the new elements to the array.

formCustomErrorMsg[formCustomErrorMsg.length] = ['name of input','Your response is required. <span>Please select the type of message. </span>'];

 

  • formCustomErrorMsg[formCustomErrorMsg.length] is the name of the array and the current position in the array.
  • 'name of input' is the input field name, text or the check box/radio button name
  • 'Your response is required. <span>Please select the type of message. </span>' is the error message that will be displayed.

For example, we have two form fields. One is a text field that has a variable name of 'Name' and we also have a text area with a field that is name 'Message'.

Example of Two fields
<form class="control-form" action="/assets/home/js/forms/forms-v3.js" name="formName" method="post" id="formId" type="external"> 
<input type="hidden" value="Subject" name="subject" /> 
<input type="hidden" value="Name, Message, name="required" id="required" /> 
<input type="hidden" value="REMOTE_HOST,HTTP_ADDR,HTTP_USER_AGENT" name="env_report" />

	<input type="text" size="40" name="Name" placeholder="Enter Your Name"/>
<textarea name="Message"></textarea> </form>

Below is the code that will be placed into the custom error JavaScript file as follows:

formCustomErrorMsg[formCustomErrorMsg.length] = ['Name','Name is required. <span>Please enter your name.</span>'];
formCustomErrorMsg[formCustomErrorMsg.length] = ['Message','Message is required. <span>Please type in your message.</span> '];
formCustomErrorMsg[formCustomErrorMsg.length] = ['g-recaptcha-response','Please check the box to indicate that you are not a robot.'];

NOTE: It is important to follow the above pattern. If it is incorrect, the form will fail to submit.

reCAPTCHA

reCAPTCHA is required on all forms and protects the form on the page from spam and abuse.

Insert the following for reCAPTCHA before the submit button to notifiy the user that we utlize reCAPTCHA and is manage by Google.

reCAPTCHA example
<div class="row">
<div class="container">
<div class="span12">
<hr />
</div>
</div>
</div>
<div class="row">
<div class="container control-group">
<div class="span12">
<p>
This site is protected by reCAPTCHA and the Google
<a href="https://policies.google.com/privacy" class="exitlink">Privacy Policy</a>
and
<a href="https://policies.google.com/terms" class="exitlink">Terms of Service</a>
apply.
</p>
</div>
</div>
</div>

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.