NYPL Design Toolkit
Version: 0.1.36NYPL Design Toolkit
- About This Toolkit
- Buttons And Menus
- Color Accessibility Table
- Color Reference
- Forms
- Layout
- General Microformats
- SVG Index
- Tables And Data
- Visible Focus
Resources
- Landmark roles & Regions
- Skip Links
- Development Checklist
- Glossary
- NYPL User Experience & Visual Design Project Index
- Visible Focus
Examples
- Discovery home
- Discovery search results
- Discovery detail page
- Discovery request page
- Discovery request form
- Discovery request confirmation page
Forms
Accessibility note: When encountering a properly formatted form, screen readers switch over to "form mode." This switch is typically signified by a loud beep. While in form mode, keyboard controls work differently, ex. "h" types a letter "h" rather than prompting the reader to scan headings. Users of screen readers and keyboard nav, generally navigate forms with the ‘Tab’ key.
Forms fields should be wrapped by a fieldset
tag. How these wrappings are determined is up to the developer’s good judgment. Recommended microformats for fieldsets are being implemented, such as the Omni Search fieldset.
Omni Search
Omni Search is a special fieldset contained in its own row, in an offsetted column. (See Layout for details.) The fieldset itself contains three child elements: a span
tag of class .nypl-omni-fields
, a text field, and a submit button
. The .nypl-omni-fields
element contains a hidden label (for screen readers only) and a select box with the applicable options.
NOTE: The text field is aria-labeledby
the button.
.nypl-omnisearch
.nypl-omni-fields
<fieldset class="nypl-omnisearch">
<span class="nypl-omni-fields">
<label for="search-by-field">Search in</label>
<select id="search-by-field">
<option value="all" selected="selected">All fields</option>
<option value="title">Title</option>
<option value="contributor">Author/Contributor</option>
<option value="subject">Subject</option>
<option value="series">Series</option>
<option value="call_number">Call number</option>
</select>
</span>
<input type="text" aria-labelledby="nypl-omni-button" value="" placeholder="Keyword, title, name, or id" />
<input type="submit" id="nypl-omni-button" value="Search">
</fieldset>
Text Fields
Text fields can include (but not rely on) a placeholder that provides additional information on the type of input it expects.
.nypl-text-field
<div class="nypl-text-field">
<label for="keyword-text">Title or description</label>
<input id="keyword-text" type="text" placeholder="Enter keywords" />
</div>
Required Fields
Required fields must include a span
tag of class nypl-required-field
in the label that includes the text “Required”. The field itself should include the required
and aria-required
attributes.
It is recommended that JavaScript-based validation be made in the onchange
event (native to select
, input[type=checkbox]
, and input[type=radio]
, also fired by some frameworks on text blur
and submit). Your designer can advise on exceptions to this recommendation if there is a good reason to do otherwise (for example, each time a user types a new letter).
Accessibility note: An optional span element with class nypl-field-status
can be included after the input field providing a brief message explaining any additional requirements about the field. If included, the note must include the aria-labelledby="[LABEL_ID] [STATUS_FIELD_ID]"
, aria-live="assertive"
, and aria-atomic="true"
attributes if the form is being validated via client-side JavaScript. The example below shows a simple validation on every key press using jQuery. See Form Validation for more information.
.nypl-required-field
<div class="nypl-text-field" id="username1">
<label for="required-field" id="username1-label">Username
<span class="nypl-required-field">Required</span>
</label>
<input id="required-field" type="text" required="true" aria-labelledby="username1-label username1-status" aria-required="true" />
<span class="nypl-field-status" id="username1-status" aria-live="assertive" aria-atomic="true">Username must only contain letters and numbers.</span>
</div>
$("#username1 #required-field").change(function (e) {
var self = $(e.target)
var text = self.val()
var regex = /\W/g
if (text.length > 0 && regex.test(text)) {
$("#username1").addClass("nypl-field-error")
$("#username1 .nypl-field-status").text("The Username must only contain letters and numbers. Try again.")
}
})
Date Fields
The date field implements a similar structure as the Text Field but uses type="date"
. This input type has limited browser support so additional server-side and JavaScript validation should be taken into consideration. Server-side validation should still occur since it is more secure.
Note: This only applies for dates that will conform to a year/month/day-style pattern (YYYY/MM/DD, MM/DD/YYYY, etc).
.nypl-date-field
<div class="nypl-date-field">
<label for="date-of-birth">Date of Birth</label>
<input id="date-of-birth" type="date" class="form-text" />
</div>
Year Fields
The year field implements a similar structure as the Text Field but uses type="number"
and expects integers (for example: 1997, 2015). It should include min
and max
attributes with the corresponding values which are up to the developer to decide what they are. A final step="1"
attribute should be included unless another step count applies. This input type has limited browser support so additional server-side and JavaScript validation should be taken into consideration. Server-side validation should still occur since it is more secure.
.nypl-year-field
<div class="nypl-year-field">
<label for="date-from">On or After Year</label>
<input id="date-from" type="number" min="1895" max="9999" step="1">
</div>
Name Fields
To be used when requesting the full names of a user in separate first and last name values. Both the first and last name input boxes should be wrapped by a div
tag and follow the basic structure of Text Fields.
.nypl-name-field
<div class="nypl-name-field">
<div>
<label for="first-text">First Name</label>
<input id="first-text" type="text" />
</div>
<div>
<label for="last-text">Last Name</label>
<input id="last-text" type="text" />
</div>
</div>
Select Boxes
.nypl-select-field
<div class="nypl-select-field">
<label for="topics">Topics</label>
<select id="topics" name="topics">
<option value="1" selected="selected">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
<option value="…">…</option>
</select>
</div>
Alphabetical Filters
Not a form element per se but still used within search forms. This control should contain a fieldset
and legend
that wrap and label it respectively. This is a list of buttons that apply an alphabetical/number-type filter. Currently applied filter is disabled. The "Any" (or multi-character) selection has a nypl-long
class.
.nypl-alphabetical-filter
<div class="nypl-alphabetical-filter">
<fieldset>
<legend>Name starts with</legend>
<button name="az-filter" disabled="true" class="nypl-long">Any</button>
<button name="az-filter" title="Show only resources with name starting with a number">#</button>
<button name="az-filter" title="Show only resources with name starting with A">A</button>
<button name="az-filter" title="Show only resources with name starting with B">B</button>
<button name="az-filter" title="Show only resources with name starting with C">C</button>
<button name="az-filter" title="Show only resources with name starting with …">…</button>
</fieldset>
</div>
Generic Checkboxes
We override the native styling of checkboxes. We change its state with css
only that allows the label and the box to be clicked to toggle it from checked or unchecked.
.nypl-generic-checkbox
<div class="nypl-generic-checkbox">
<input id="book-check-filter" class="switch-input" type="checkbox" name="format" value="Book" />
<label for="book-check-filter">The Checkbox Label</label>
</div>
Terms / Opt-in Checkboxes
For situations where the user is requested to accept a terms of service or to opt-in to communications from the Library. When checked, a class of checked
should be added to the main element.
.nypl-terms-checkbox
.checked
<div class="nypl-terms-checkbox">
<label for="checkbox-optin">
<input id="checkbox-optin" type="checkbox" value="1" />Yes, I'd like to receive e-communications about NYPL's programs, services, and initiatives.
</label>
</div>
$("#checkbox-optin").change(function(e){
var checked = e.target.checked
if (checked) {
$(".nypl-terms-checkbox").addClass("checked")
} else {
$(".nypl-terms-checkbox").removeClass("checked")
}
})
Radiobutton/Checkbox Groups
Another control that contains a fieldset
and its corresponding legend
.
Accessibility note: For proper screen reader behavior, each radiobutton or checkbox must be aria-labelledby
both the title legend
tag and its corresponding label
tag.
.nypl-radiobutton-field
NOTE: In this case the input tags are wrapped by the label
tag.
<div class="nypl-radiobutton-field">
<fieldset>
<legend id="radiobutton-group1">Accessible from</legend>
<label id="radiobutton-group1_every" for="available-every">
<input aria-labelledby="radiobutton-group1 radiobutton-group1_every" id="available-every" type="radio" name="available" value="any" />Anywhere
</label>
<label id="radiobutton-group1_home" for="available-home">
<input aria-labelledby="radiobutton-group1 radiobutton-group1_home" id="available-home" type="radio" name="available" value="home" />Home with a library card
</label>
<label id="radiobutton-group1_library" for="available-library">
<input aria-labelledby="radiobutton-group1 radiobutton-group1_library" id="available-library" type="radio" name="available" value="library" />A library branch
</label>
</fieldset>
</div>
Collapsible Fields
Collapsible fields group multiple form fields into a collapsible box. This allows for better organization and display of multiple visually different form fields.
The general structure is:
- a
nypl-facet-toggle
toggle button that controls the open/closed state of the widget with the facet name wrapped in anh3
tag, - a div of class
nypl-collapsible
which contains the fields.
Accessibility note: The toggle button must wrap the facet name with an h3
tag.
Toggling between closed and open states along with the affected aria-expanded
values of the widget will be controlled via JavaScript. A collapsed
class must be added (or removed) to the nypl-collapsible-field
and nypl-collapsible
elements. The example below uses jQuery.
NOTE: The widget defaults to the open state but is closed via JavaScript on page load. This is to support situations where JavaScript may be disabled and allow users to see and interact with the facets.
.nypl-collapsible-field
.nypl-collapsible
.collapsed
<div class="nypl-collapsible-field" aria-expanded="true">
<button type="button" id="date" class="nypl-facet-toggle"
aria-controls="nypl-collapsible-field_date" aria-expanded="true">
<h3>Date</h3>
<svg aria-hidden="true" class="nypl-icon" preserveAspectRatio="xMidYMid meet" viewBox="0 0 68 24"><title>wedge down icon</title><polygon points="67.938 0 34 24 0 0 10 0 34.1 16.4 58.144 0 67.938 0" /></svg>
</button>
<div class="nypl-collapsible" id="nypl-collapsible-field_date" aria-expanded="true">
<div class="nypl-year-field">
<label for="date-from1">On or After Year</label>
<input id="date-from1" type="number" min="0" max="9999" step="1">
</div>
<div class="nypl-year-field">
<label for="date-to1">On or Before Year</label>
<input id="date-to1" type="number" min="0" max="9999" step="1">
</div>
</div>
</div>
// jQuery example
$("button.nypl-facet-toggle").click(function (e) {
toggleFacet(e)
})
function toggleFacet(e) {
var button = $(e.target)
var facet = button.parent()
var collapsible = facet.find(".nypl-collapsible")
button.attr("aria-expanded", button.attr("aria-expanded") == "false" ? "true" : "false")
facet.attr("aria-expanded", facet.attr("aria-expanded") == "false" ? "true" : "false")
collapsible.attr("aria-expanded", collapsible.attr("aria-expanded") == "false" ? "true" : "false")
facet.toggleClass("collapsed")
collapsible.toggleClass("collapsed")
}
Searchable Fields
Searchable are a version of the collapsible fieldsets that allow the user to see many non-exclusive options at the same time while also searching within the option list. Use searchable facets when the list of potential selectable items is too large (i.e. more than a dozen or so). The text field should autocomplete (with result count) as the user types in it. By default, show the top 10 items sorted by the amount of results that will be returned.
The general structure is:
- a
nypl-facet-toggle
toggle button that controls the open/closed state of the widget with the facet name wrapped in anh3
tag, - a div of class
nypl-collapsible
which contains: - a
nypl-facet-search
that reflects the general structure of a text field element followed by - a fieldset of class
nypl-facet-list
with - each of the possible facet values as described below.
Each facet value checkbox has the following structure (note that the result count comes before the facet text):
<label id="my-facet-label-id" for="my-facet-value-id" class="nypl-bar_[1 to 100]">
<input aria-labelledby="my-facet-label-id my-facet-value-id" id="my-facet-value-id" type="checkbox" name="my-name" value="my-value" />
<span class="nypl-facet-count">[estimated result count]</span>
<span>The facet text</span>
</label>
The placeholder on the search box should have the text “Search [facetname plural]” to make clear that the user is searching within the possible values to facet on.
The label has an optional class of nypl-bar_[percentnumber]
where the [percentnumber]
determines the length of the decorative bar behind the value and should reflect the relative size of the selection of that facet. It must be an integer from 1 to 100, from shortest to longest (this is a different number from the estimated result count). A label with class nypl-bar_10
would be 10% long, from the right.
The facet count is optional but must be of class nypl-facet-count
.
Accessibility note: Similar to Radiobutton/Checkbox Groups, for proper screen reader behavior, each radiobutton or checkbox must be aria-labelledby
both the title group's button
tag and its own corresponding label
tag.
Accessibility note: The toggle button must wrap the facet name with an h3
tag.
A “Show X more” link button at the end of the list allows for the user to display X more items to select from. Important: When the facet has very few items or when no “Show X more” button is displayed, the class nosearch
has to be added to the field. This will hide the search box.
Toggling between closed and open states along with the affected aria-expanded
values of the widget will be controlled via JavaScript. A collapsed
class must be added (or removed) to the nypl-searchable-field
and nypl-collapsible
elements. The example below uses jQuery.
NOTE: Place previously checked items first and without the number. The widget defaults to the open state but is closed via JavaScript on page load. This is to support situations where JavaScript may be disabled and allow users to see and interact with the facets.
NOTE: As is the case of the Radio Buttons In this case the input tags are wrapped by the label
tag.
.nypl-searchable-field
.nypl-facet-search
.nypl-facet-list
.nypl-facet-count
.nypl-collapsible
.collapsed
<div class="nypl-searchable-field" aria-expanded="true">
<button type="button" id="searchable1" class="nypl-facet-toggle"
aria-controls="nypl-searchable-field_facet1" aria-expanded="true">
<h3>Subject</h3>
<svg aria-hidden="true" class="nypl-icon" preserveAspectRatio="xMidYMid meet" viewBox="0 0 68 24"><title>wedge down icon</title><polygon points="67.938 0 34 24 0 0 10 0 34.1 16.4 58.144 0 67.938 0" /></svg>
</button>
<div class="nypl-collapsible" id="nypl-searchable-field_facet1" aria-expanded="true">
<div class="nypl-facet-search">
<label for="subject-text">Search within Subjects</label>
<input id="subject-text" type="text" />
</div>
<fieldset class="nypl-facet-list">
<label id="subject_poems" for="subject-poems">
<input aria-labelledby="searchable1 subject_poems" id="subject-poems" type="checkbox" name="subject" value="poems" checked="checked" />
<span>Poems</span>
</label>
<label id="subject_ejournals" for="subject-ejournals" class="nypl-bar_43">
<input aria-labelledby="searchable1 subject_ejournals" id="subject-ejournals" type="checkbox" name="subject" value="ejournals" />
<span class="nypl-facet-count">1,334,741</span>
<span>Electronic journals</span>
</label>
<label id="subject_home" for="subject-home" class="nypl-bar_21">
<input aria-labelledby="searchable1 subject_home" id="subject-home" type="checkbox" name="subject" value="home" />
<span class="nypl-facet-count">236</span>
<span>Electronic books</span>
</label>
<label id="subject_piano" for="subject-piano" class="nypl-bar_18">
<input aria-labelledby="searchable1 subject_piano" id="subject-piano" type="checkbox" name="subject" value="piano" />
<span class="nypl-facet-count">198</span>
<span>Piano music</span>
</label>
<label id="subject_opera" for="subject-opera" class="nypl-bar_11">
<input aria-labelledby="searchable1 subject_opera" id="subject-opera" type="checkbox" name="subject" value="opera" />
<span class="nypl-facet-count">122</span>
<span>Operas</span>
</label>
</fieldset>
<button class="nypl-link-button">Show 10 more</button>
</div>
</div>
// jQuery example
$("button.nypl-facet-toggle").click(function (e) {
toggleFacet(e)
})
function toggleFacet(e) {
var button = $(e.target)
var facet = button.parent()
var collapsible = facet.find(".nypl-collapsible")
button.attr("aria-expanded", button.attr("aria-expanded") == "false" ? "true" : "false")
facet.attr("aria-expanded", facet.attr("aria-expanded") == "false" ? "true" : "false")
collapsible.attr("aria-expanded", collapsible.attr("aria-expanded") == "false" ? "true" : "false")
facet.toggleClass("collapsed")
collapsible.toggleClass("collapsed")
}
Form Validation
Form validation should be handled such that it works even if JavaScript is disabled by the user. Client-side validation is useful to prevent invalid input beforehand, but can be unreliable. Make sure to do additional server-side validation of any user input.
Form validation includes two aspects: form-level messages and field-level messages.
Error messages for the submitted form
When the form has been submitted, errors or problems with individual fields must be hightlighted and focused at the top of the form and linked internally to the individual fields. The components are: a div
element of class nypl-form-error
, a heading informing the user that errors have occurred should be used, a child list with the individual field errors. The field errors must link to the field itself to make it easier for users to find it within the form:
.nypl-form-error
<div class="nypl-form-error">
<h2>Oops! Seems there are some errors in this form!</h2>
<ul>
<li>The <a href="#">username</a> already exists. Please choose another username.</li>
<li>The <a href="#">email</a> is invalid.</li>
</ul>
</div>
Success / Completion messages for the submitted form
In the case were the form has been submitted and the application needs to alert the user that their data or input has been submitted and accepted. Similar to the above error reporting, the components are: a div
element of class nypl-form-success
, a heading informing the user the their submission has been accepted by the application, either via front-end, server side validation or as the case may be both, and short secondary message with an explantion (optional) wrapped in a p
.
Success!
Your form has been accepted.
.nypl-form-success
<div class="nypl-form-success">
<h2>Success!</h2>
<p>Your form has been accepted.</p>
</div>
Error state and messages on text fields
Any field where user input could be erroneous should add the class nypl-field-error
upon validation. It is up to the product designer to determine what fields should have an error state and provide correct explanatory text using an nypl-field-status
as described in Required Fields. It is the responsibility of the developer to implement the necessary validations.
Accessibility note: The correct aria
attributes must be added to the input
field for proper accessibility coverage. The example below describes both aria-required
and aria-invalid
. aria-required
will be a static state for the form, whereas aria-invalid
will initially be set to false
, upon a an invalid submission, the attribute should return true
as it's value. The field must also make use of the nypl-field-status
span
element as described in Required Fields above. The example below provides a very simple jQuery-based implementation. See also Basic Form Hints: Required and invalid fields in the Mozilla Developer Network.
.nypl-field-error
<div class="nypl-text-field nypl-field-error" id="email1">
<label for="email-field">Email
<span class="nypl-required-field">Required</span>
</label>
<input aria-required="true" aria-invalid="true" id="email-field" type="text" placeholder="" value="sally ride" />
<span class="nypl-field-status" aria-live="assertive" aria-atomic="true">Email address must use the correct formatting. Ex: <em>prudence@example.org</em></span>
</div>
$("#email1 #email-field").blur(function (e) {
var self = $(e.target)
var text = self.val()
var regex = /^[^@\s]+@[^@\s]+\.[^@\s]+/
if (!regex.test(text)) {
$("#email1").addClass("nypl-field-error")
$("#email1 .nypl-field-status").text("The Email address must use the correct formatting. Example: prudence@example.org. Try again.")
} else {
$("#email1").removeClass("nypl-field-error")
$("#email1 .nypl-field-status").text("")
self.attr("aria-invalid", "false")
}
})
Fields With Spinners
Use these spinners when the interface being developed updates remotely (via AJAX calls or similar) instead of a regular page refresh to indicate the user that background processing is happening. This prevents user confusion and error.
The main field element (whether a div or fieldset) must include an additional nypl-spinner-field
class. Once the user submits or makes changes in the field that produce a remote request, an additional spinning
class should be activated so that an animation is displayed overlaying it.
Important: While the overlay prevents some user input, the necessary precautions of disabling and/or blurring elements within the field should also be taken into account.
Accessibility note: This is a visual-only progressive enhancement recommendation and should not be relied on as the only indicator of state.
.nypl-spinner-field
.spinning
<fieldset class="nypl-omnisearch nypl-spinner-field">
<input type="text" aria-labelledby="nypl-omni-button1" value="" />
<span class="nypl-omni-fields">
<label for="search-by-field1">Search in</label>
<select id="search-by-field1"><option value="all">All fields</option><option value="title">Title</option><option value="contributor">Author/Contributor</option><option value="subject">Subject</option><option value="series">Series</option><option value="call_number">Call number</option></select>
</span>
<input type="submit" id="nypl-omni-button1" value="Search">
</fieldset>
<div class="nypl-text-field nypl-spinner-field">
<label for="keyword-text2">Title or description</label>
<input id="keyword-text2" type="text" placeholder="Enter keywords" />
</div>
<div class="nypl-select-field nypl-spinner-field">
<label for="topics2">Topics</label>
<select id="topics2" name="topics">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
<option value="…">…</option>
</select>
</div>
<div class="nypl-alphabetical-filter nypl-spinner-field">
<fieldset>
<legend>Name starts with</legend>
<button name="az-filter" disabled="true" class="nypl-long">Any</button>
<button name="az-filter" title="Show only resources with name starting with a number">#</button>
<button name="az-filter" title="Show only resources with name starting with A">A</button>
<button name="az-filter" title="Show only resources with name starting with B">B</button>
<button name="az-filter" title="Show only resources with name starting with C">C</button>
<button name="az-filter" title="Show only resources with name starting with …">…</button>
</fieldset>
</div>
<div class="nypl-radiobutton-field nypl-spinner-field">
<fieldset>
<legend id="radiobutton-group2">Accessible from</legend>
<label id="radiobutton-group2_every" for="available-every2">
<input aria-labelledby="radiobutton-group2 radiobutton-group2_every" id="available-every2" type="radio" name="available2" value="any" />
<span>Anywhere</span>
</label>
<label id="radiobutton-group2_home" for="available-home2">
<input aria-labelledby="radiobutton-group2 radiobutton-group2_home" id="available-home2" type="radio" name="available2" value="home" />
<span>Home with a library card</span>
</label>
<label id="radiobutton-group2_library" for="available-library2">
<input aria-labelledby="radiobutton-group2 radiobutton-group2_library" id="available-library2" type="radio" name="available2" value="library" />
<span>A library branch</span>
</label>
</fieldset>
</div>
<div class="nypl-searchable-field nypl-spinner-field" aria-expanded="true">
<button type="button" id="searchable2" class="nypl-facet-toggle"
aria-controls="nypl-searchable-field_subject" aria-expanded="true">
Subject
<svg aria-hidden="true" class="nypl-icon" preserveAspectRatio="xMidYMid meet" viewBox="0 0 68 24">
<title>wedge down icon</title>
<polygon points="67.938 0 34 24 0 0 10 0 34.1 16.4 58.144 0 67.938 0" />
</svg>
</button>
<div class="nypl-collapsible" id="nypl-searchable-field_subject" aria-expanded="false">
<div class="nypl-facet-search">
<label id="searchable2-label" for="subject-text2">Search within Subjects</label>
<input id="subject-text2" type="text" />
</div>
<fieldset class="nypl-facet-list">
<label id="subject_poems2" for="subject-poems2">
<input aria-labelledby="searchable2 subject_poems2" id="subject-poems2" type="checkbox" name="subject2" value="poems" checked="checked" />
<span>Poems</span>
</label>
<label id="subject_ejournals2" for="subject-ejournals2" class="nypl-bar_43">
<input aria-labelledby="searchable2 subject_ejournals2" id="subject-ejournals2" type="checkbox" name="subject2" value="ejournals" />
<span class="nypl-facet-count">1,334,741</span>
<span>Electronic journals</span>
</label>
<label id="subject_home2" for="subject-home2" class="nypl-bar_21">
<input aria-labelledby="searchable2 subject_home2" id="subject-home2" type="checkbox" name="subject2" value="home" />
<span class="nypl-facet-count">236</span>
<span>Electronic books</span>
</label>
<label id="subject_piano2" for="subject-piano2" class="nypl-bar_18">
<input aria-labelledby="searchable2 subject_piano2" id="subject-piano2" type="checkbox" name="subject2" value="piano" />
<span class="nypl-facet-count">198</span>
<span>Piano music</span>
</label>
<label id="subject_opera2" for="subject-opera2" class="nypl-bar_11">
<input aria-labelledby="searchable2 subject_opera2" id="subject-opera2" type="checkbox" name="subject2" value="opera" />
<span class="nypl-facet-count">122</span>
<span>Operas</span>
</label>
</fieldset>
<button class="nypl-link-button">Show 10 more</button>
</div>
</div>
// example jQuery-based activation code
function makeItSpin(who, input) {
$(who).toggleClass("spinning");
if (input) $(input).attr("disabled", "true").blur();
setTimeout(function () {
$(who).toggleClass("spinning")
if (input) $(input).removeAttr("disabled");
}, 2000)
}
$(".nypl-omnisearch.nypl-spinner-field #nypl-omni-button1").click( function(e) {
var self = $(e.target)
makeItSpin(self.parent(), self)
})
$(".nypl-omnisearch.nypl-spinner-field input[type=text]").change( function(e) {
var self = $(e.target)
makeItSpin(self.parent(), self)
})
$(".nypl-text-field.nypl-spinner-field input").change( function(e) {
var self = $(e.target)
makeItSpin(self.parent())
})
$(".nypl-select-field.nypl-spinner-field select").change( function(e) {
var self = $(e.target)
makeItSpin(self.parent(), self)
})
$(".nypl-alphabetical-filter.nypl-spinner-field button").click( function(e) {
var self = $(e.target)
makeItSpin(self.parent().parent())
})
$(".nypl-radiobutton-field.nypl-spinner-field fieldset").change( function(e) {
var self = $(e.target)
makeItSpin(self.parent().parent().parent(), self.parent().parent())
})
$(".nypl-searchable-field.nypl-spinner-field #subject-text2").change( function(e) {
var self = $(e.target)
makeItSpin(self.parent().parent())
})
$(".nypl-searchable-field.nypl-spinner-field fieldset").change( function(e) {
var self = $(e.target)
makeItSpin(self.parent().parent().parent(), self.parent().parent())
})
Basic Text Areas
In the case where an application form needs a mulitline text-area
NOTE: Your application may require this input from the user, in that case, before the closing </label>
add the following <span class="nypl-required-field">Required</span>
. This adds the existing style for required fields via the .nypl-required-field
class.
.nypl-text-area-with-label
<div class="nypl-text-area-with-label">
<label for="textarea1">Text Area Label</label>
<textarea form="the-form-title" id="textarea1" name="application-text-area"></textarea>
<span class="nypl-field-status" aria-live="assertive" aria-atomic="true">The application is expecting a certain kind of input. The application developer should describe that criteria in this space.</span>
</div>
Text Area (Accepted)
In cases were the application is performing client side validation onblur
the text area should confirm that the user’s input is indeed what the application is expecting.
.nypl-text-area-with-label
.nypl-field-success
<div class="nypl-text-area-with-label nypl-field-success">
<label for="textarea1">Text Area Label</label>
<textarea form="the-form-title" id="textarea1" name="application-text-area"></textarea>
<span class="nypl-field-status" aria-live="assertive" aria-atomic="true">The input was correct</span>
</div>
Text Area (Error)
In cases were the application is performing client side validation onblur
the text area should confirm that the user&rsuqo;s input is incorrect and should be corrected before the application will accept submission. Additional reporting of errors should be presented to the user in the form the Error Message pattern described above.
.nypl-text-area-with-label
.nypl-field-error
<div class="nypl-text-area-with-label nypl-field-error">
<label for="textarea1">Text Area Label </label>
<textarea form="the-form-title" id="textarea1" name="application-text-area"></textarea>
<span class="nypl-field-status" aria-live="assertive" aria-atomic="true">The input provided has errors and must be corrected before submission can be complete.</span>
</div>