As of January 3rd, 2023 the Working NYC Pattern library package is deprecated in favor of the NYC Opportunity Standard which contains updated user interface elements and usability guidance.
Newsletter
The Newsletter Object is an embedded MailChimp signup form. More details about embedded MailChimp forms can be found on the MailChimp website. This form can work with any Mailchimp subscriber list that is configured through the form action;
form action="https://nyc.us18.list-manage.com/subscribe/post?u={{ mailchimp account }}&id={{ form id }}" method="post" id="mc-embedded-subscribe-form"
While the Newsletter Object doesn’t require JavaScript, it is needed for submitting the form without leaving the page and for front-end validation.
Demonstration
Markup
<section class="o-newsletter layout-content py-6" data-js="newsletter"> <div class="pt-2 pb-3 wrap"> <h2 class="o-newsletter__heading h4 font-normal">Newsletter</h2> <form action="https://nyc.us18.list-manage.com/subscribe/post?u=d04b7b607bddbd338b416fa89&id=aa67394696" id="mc-embedded-subscribe-form" method="post" target="_blank"> <div class="c-question c-question-single" id="6bac56721dde9"> <!--{ @for Should match the id of the input }--> <label class="c-question__label" for="question-6bac56721dde9">Enter your email to sign up for our newsletter and stay up-to-date with careers, training, and events.</label> <div class="c-question__container"> <div class="c-question__input"> <div class="input"> <!--{ @required required="true" specifies wether the input is required by a form }--> <!--{ @pattern pattern="{{ my regular expression }}" a regular expression the input's value must match in order to validate }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="question-6bac56721dde9" name="EMAIL" placeholder="Enter your email" required="true" type="email" /> </div> <div class="c-question__button"> <button class="btn btn-primary btn-small" type="submit">Submit</button> </div> </div> </div> </div> </form> </div> </section>
Demonstration
Markup
<div data-js="newsletter-form"> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <form action="https://nyc.us18.list-manage.com/subscribe/post?u=d04b7b607bddbd338b416fa89&id=aa67394696" id="mc-embedded-subscribe-form" method="post" target="_blank"> <!--{ @data-js This selector is recommended for JavaScript enhanced alerts but not necessary }--> <article aria-hidden="true" class="c-alert status-tertiary mb-5 hidden" data-js="alert-warning"> <div class="c-alert__graphic"> <svg aria-hidden="true" class="icon-wnyc-ui"> <use href="#feather-info"></use> </svg> </div> <!--{ @aria-live Setting aria-live="polite" dynamically is recommended for new content that appears based on user interaction }--> <div class="c-alert__body"> <!--{ @data-js-alert This selector is recommended for JavaScript enhanced alerts but not necessary }--> <p data-js-alert='text'></p> </div> </article> <!--{ @data-js This selector is recommended for JavaScript enhanced alerts but not necessary }--> <article aria-hidden="true" class="c-alert status-secondary mb-5 hidden" data-js="alert-success"> <div class="c-alert__graphic"> <svg aria-hidden="true" class="icon-wnyc-ui"> <use href="#feather-info"></use> </svg> </div> <!--{ @aria-live Setting aria-live="polite" dynamically is recommended for new content that appears based on user interaction }--> <div class="c-alert__body"> <!--{ @data-js-alert This selector is recommended for JavaScript enhanced alerts but not necessary }--> <p data-js-alert='text'></p> </div> </article> <div class="c-question " id="a6d9c914f8a42"> <!--{ @for Should match the id of the input }--> <label class="c-question__label" for="question-a6d9c914f8a42">Your email address.</label> <div class="c-question__container"> <div class="input"> <!--{ @required required="true" specifies wether the input is required by a form }--> <!--{ @pattern pattern="{{ my regular expression }}" a regular expression the input's value must match in order to validate }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="question-a6d9c914f8a42" name="EMAIL" required="true" type="email" /> </div> </div> </div> <div class="c-question " id="5aa7007664da3"> <!--{ @for Should match the id of the input }--> <label class="c-question__label" for="question-5aa7007664da3">What is your zip code?</label> <div class="c-question__container"> <div class="input"> <!--{ @required required="true" specifies wether the input is required by a form }--> <!--{ @pattern pattern="{{ my regular expression }}" a regular expression the input's value must match in order to validate }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="question-5aa7007664da3" name="ZIPCODE" required="true" type="text" /> </div> </div> </div> <!--{ @fieldset Checkbox and radio input groups should be grouped in fieldset tags }--> <fieldset class="c-question" id="9aef508f0fb4b"> <!--{ @legend Checkboxes and radio input groups should be labeled by legend tags }--> <legend class="c-question__label">Which borough(s) would you like to recieve updates for?</legend> <div class="c-question__container grid grid-cols-1 tablet:grid-cols-2 gap-2"> <!--{ @for Should match the id of the input }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <label class="option mb-0" for="mce-group[4369]-4369-0"> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="mce-group[4369]-4369-0" name="group[4369][1]" type="checkbox" value="1" /> <span class="option__base"> <svg aria-hidden="true" class="option__graphic"> <use href="#option-wnyc-checkbox"></use> </svg> <span class="option__label">Bronx</span> </span> </label> <!--{ @for Should match the id of the input }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <label class="option mb-0" for="mce-group[4369]-4369-4"> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="mce-group[4369]-4369-4" name="group[4369][16]" type="checkbox" value="16" /> <span class="option__base"> <svg aria-hidden="true" class="option__graphic"> <use href="#option-wnyc-checkbox"></use> </svg> <span class="option__label">Staten Island</span> </span> </label> <!--{ @for Should match the id of the input }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <label class="option mb-0" for="mce-group[4369]-4369-3"> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="mce-group[4369]-4369-3" name="group[4369][8]" type="checkbox" value="8" /> <span class="option__base"> <svg aria-hidden="true" class="option__graphic"> <use href="#option-wnyc-checkbox"></use> </svg> <span class="option__label">Queens</span> </span> </label> <!--{ @for Should match the id of the input }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <label class="option mb-0" for="mce-group[4369]-4369-1"> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="mce-group[4369]-4369-1" name="group[4369][2]" type="checkbox" value="2" /> <span class="option__base"> <svg aria-hidden="true" class="option__graphic"> <use href="#option-wnyc-checkbox"></use> </svg> <span class="option__label">Brooklyn</span> </span> </label> <!--{ @for Should match the id of the input }--> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <label class="option mb-0" for="mce-group[4369]-4369-2"> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <input id="mce-group[4369]-4369-2" name="group[4369][4]" type="checkbox" value="4" /> <span class="option__base"> <svg aria-hidden="true" class="option__graphic"> <use href="#option-wnyc-checkbox"></use> </svg> <span class="option__label">Manhattan</span> </span> </label> </div> </fieldset> <!--{ This is a hidden input to help prevent spam }--> <div aria-hidden="true" style="position: absolute; left: -5000px;"> <input name="b_d04b7b607bddbd338b416fa89_98ff3f3900" tabindex="-1" type="text" value="" /> </div> <!--{ @tabindex Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }--> <button class="btn-primary" type="submit">Submit</button> </form> </div>
Global Script
While the Newsletter Object doesn’t require JavaScript, it is needed for submitting the form without leaving the page and for front-end validation.
<script src="/dist/scripts/main.js"></script>
<script>
var patterns = new WorkingNyc();
patterns.newsletter('/path/to/full/form');
patterns.newsletterForm();
</script>
patterns.newsletter('/path/to/full/form')
instantiates the default Newsletter form field. It will pass the data from the MailChimp subscription response as URL parameters to a specified endpoint set as the first (and only) argument.
patterns.newsletterForm()
instantiates the Full Newsletter form field. It will automatically handle the response passed as URL parameters from the single form field and display the response for the submission.
Note. It is recommended that data passed via URL parameters be validated.
Module Import
The Newsletter source exists in the NYCO Patterns Framework. Install the @nycopportunity/patterns-framework
module to import the module. Pass a selected newsletter element that contains the form to the instantiated object and set the parent selector for input validation messaging.
import Newsletter from '@nycopportunity/patterns-framework/src/utilities/newsletter/newsletter';
let element = document.querySelector('[data-js="newsletter-form"]');
let newsletter = new Newsletter(element);
newsletter.form.selectors.ERROR_MESSAGE_PARENT = '.c-question__container';
Setting a custom callback
The patterns.newsletter()
method uses a custom callback to the window that the MailChimp subscription endpoint sends response data to. Below is an example of this.
// ...
let newsletter = new Newsletter(element);
// ...
// Use the instantiated Newsletter's unique callback key
window[newsletter.callback] = data => {
data.response = true;
// Set email to the data so it is passed along
data.email = element.querySelector('input[name="EMAIL"]').value;
// Set the window location to redirect to the form with URL parameters from the response
window.location = '/path/to/full/form?' + Object.keys(data)
.map(k => `${k}=${encodeURI(data[k])}`).join('&');
};
Pre-populating a response
The patterns.newsletterForm()
Below is an example the global script uses to prepopulate the Newsletter response in the full form using URL parameters.
// ...
let newsletter = new Newsletter(element);
// ...
let params = new URLSearchParams(window.location.search);
let email = params.get('email');
let input = element.querySelector('input[name="EMAIL"]');
// Populate the email field on the form
input.value = email;
// Set the instantiated Newsletter's data store
newsletter._data = {
result: params.get('result'),
msg: params.get('msg'),
EMAIL: email
};
// Pass the data to the Newsletter's callback function for displaying messaging
newsletter._callback(newsletter._data);
View the patterns.newsletterForm()
method source at /src/js/main.js for a full example.