Question

The Question Component allows a user to enter information into a form. This pattern follows the usage guidelines of the U.S. Web Design System’s Form Control.

Validation and Accessibility

Question Components in this demonstration use validation from the Form Utility in the NYCO Patterns Framework. This script will display visual feedback regarding missing and invalid answers to the user as well as toggle appropriate aria attributes for announcing feedback to screen readers. The aria-live=”polite” attribute on the message announces a new element that was not previously visible in the default Question Component state. Additionally, the aria-invalid=”true” attribute illustrates to screen readers that the input is not valid and the aria-describedby attribute indicates the input’s error description. See more details about using validation below.

Demonstration

Answer to the best of your ability.

Markup
<div class="c-question " id="ff03c5a506e91">
  <!--{ @for  Should match the id of the input }-->
  <label class="c-question__label" for="question-ff03c5a506e91">Will you please fill out this required question?</label>
  <p>Answer to the best of your ability.</p>
  <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-ff03c5a506e91" name="question['ff03c5a506e91']" type="text" />
    </div>
  </div>
</div>
Demonstration
Will you please select an option from the list below?

Feel free to select more than one option.

Markup
<!--{ @fieldset  Checkbox and radio input groups should be grouped in fieldset tags }-->
<fieldset class="c-question" id="10628bb786ee5">
  <!--{ @legend  Checkboxes and radio input groups should be labeled by legend tags }-->
  <legend class="c-question__label">Will you please select an option from the list below?</legend>
  <p>Feel free to select more than one option.</p>
  <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="4cc45d1bd4c5e">
      <!--{ @tabindex  Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }-->
      <input id="4cc45d1bd4c5e" name="option['4cc45d1bd4c5e']" type="checkbox" value="option-1" />
      <span class="option__base">
        <svg aria-hidden="true" class="option__graphic">
          <use href="#option-wnyc-checkbox"></use>
        </svg>
        <span class="option__label">Option 1</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="96b11d942fcaf">
      <!--{ @tabindex  Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }-->
      <input id="96b11d942fcaf" name="option['96b11d942fcaf']" type="checkbox" value="option-2" />
      <span class="option__base">
        <svg aria-hidden="true" class="option__graphic">
          <use href="#option-wnyc-checkbox"></use>
        </svg>
        <span class="option__label">Option 2</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="1438ed9c9b801">
      <!--{ @tabindex  Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }-->
      <input id="1438ed9c9b801" name="option['1438ed9c9b801']" type="checkbox" value="option-3" />
      <span class="option__base">
        <svg aria-hidden="true" class="option__graphic">
          <use href="#option-wnyc-checkbox"></use>
        </svg>
        <span class="option__label">Option 3</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="699e9bd62e553">
      <!--{ @tabindex  Add tabindex="-1" to insure focusable elements are not visible when parent is hidden }-->
      <input id="699e9bd62e553" name="option['699e9bd62e553']" type="checkbox" value="option-4" />
      <span class="option__base">
        <svg aria-hidden="true" class="option__graphic">
          <use href="#option-wnyc-checkbox"></use>
        </svg>
        <span class="option__label">Option 4</span>
      </span>
    </label>
  </div>
</fieldset>
Demonstration
Markup
<div class="c-question c-question-single" id="cfded1e52c78b">
  <!--{ @for  Should match the id of the input }-->
  <label class="c-question__label" for="question-cfded1e52c78b">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-cfded1e52c78b" 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>
Global Script

The Question Component requires JavaScript for native form validation. To use the validation through the global script use the following code. A optional selector targeting the form may be supplied as the first argument to the .validate() method. The second optional argument is a function which handles the form data after it passes validation.

<script src="/dist/scripts/main.js"></script>

<script>
  var patterns = new WorkingNyc();

  patterns.validate();

  // or

  // Accepts a @selector and @function for submission handling
  patterns.validate('#a-custom-form', function(event) {
    event.preventDefault();
    // A custom submission handler
  });
</script>
Markup
<form data-js="validate" action="/my/action/" method="post">
  <label for="email">Please enter your email.</label>

  <input type="email" id="email" required="true">

  <button>Submit</button>
</form>

Validation messages will appear when the user leaves a required question blank (required="true" must be set on the <input> tag), enters an answer that does not match a specified pattern (pattern="{{ my regular expression }}" must be set on the <input> tag), or tries to submit the form without filling out any required fields.

Module Import

The form validation source exisits in the NYCO Patterns Framework. Install the @nycopportunity/patterns-framework module to import that script. This method allows the specification of watching for input errors on blur, setting the error container’s selector, and other customizations. See the source for details.

import Forms from '@nycopportunity/patterns-framework/src/utilities/forms/forms';

this.form = new Forms(document.querySelector('#question-demo'));

this.form.submit = (event) => {
  event.preventDefault();
  // Submission handler
};

this.form.selectors.ERROR_MESSAGE_PARENT = '.c-question__container';

this.form.watch();