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

Newsletter

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&amp;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
Which borough(s) would you like to recieve updates for?
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&amp;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.