18F/web-design-standards

View on GitHub
packages/usa-form/src/test/test-pattern/test-usa-form.twig

Summary

Maintainability
Test Coverage
{# *
* While we could add the usa-form-group--error class to <form class="usa-form"> elements, we should 
* avoid doing this and only add it to usa-form-group elements.
*
* Setting the error on the form element would add the error class to the entire form and not just 
* the form question that holds the error.
*#}
<form class="usa-form">
  <div class="usa-character-count">
    <div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
      <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="with-hint-input">Character count</label>
      <span id="with-hint-input-hint" class="usa-hint">This is an input with a character counter.</span>
      {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
      <input
        class="usa-input usa-character-count__field {% if error_state == true %}usa-input--error{% endif %}"
        id="with-hint-input"
        maxlength="25"
        name="with-hint-input"
        aria-describedby="with-hint-input-info with-hint-input-hint"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}>
    </div>
    <span id="with-hint-input-info" class="usa-character-count__message">You can enter up to 25 characters</span>
  </div>
</form>


{# *
* usa-legend and usa-label output the same base styles. Because of this, we can add the 
* usa-label--error class without any additional changes or unexpected style conflicts.
*#}
<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <fieldset class="usa-fieldset margin-top-2">
    <legend class="usa-legend {% if error_state == true %}usa-label--error{% endif %}">Checkbox</legend>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <div class="usa-checkbox">
      <input
        class="usa-checkbox__input usa-input--error"
        id="check-historical-washington"
        type="checkbox"
        name="historical-figures"
        value="booker-t-washington"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      />
      <label class="usa-checkbox__label" for="check-historical-washington"
        >Booker T. Washington</label
      >
    </div>
    <div class="usa-checkbox">
      <input
        class="usa-checkbox__input"
        id="check-historical-carver"
        type="checkbox"
        name="historical-figures"
        value="george-washington-carver"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      />
      <label class="usa-checkbox__label" for="check-historical-carver"
        >George Washington Carver</label
      >
    </div>
  </fieldset>
</div>

{# *
* In order for the red border to highlight the form input with an error, the elements must be 
* nested within a div with the usa-form-group and usa-form-group--error classes.
*#}
<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <fieldset class="usa-fieldset margin-top-2">
  <legend class="usa-legend {% if error_state == true %}usa-label--error{% endif %}">Radio</legend>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <div class="usa-radio">
      <input
        class="usa-radio__input"
        id="historical-washington"
        type="radio"
        name="historical-figures"
        value="booker-t-washington"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      />
      <label class="usa-radio__label" for="historical-washington"
        >Booker T. Washington</label
      >
    </div>
    <div class="usa-radio">
      <input
        class="usa-radio__input"
        id="historical-carver"
        type="radio"
        name="historical-figures"
        value="george-washington-carver"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      />
      <label class="usa-radio__label" for="historical-carver"
        >George Washington Carver</label
      >
    </div>
  </fieldset>
</div>

{# ! 
! Adding the usa-input--error class to the combo box nested select element does not carry the class over to 
! its dynamically placed input element. The class remains on the hidden select element. This is true for time picker's 
! combo box element as well.
!#}
<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="fruit">Combo box</label>
  {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
  <div class="usa-combo-box">
    <select
      class="usa-select {% if error_state == true %}usa-input--error{% endif %}"
      name="fruit"
      id="fruit"
      {% if disabled_state == 'disabled' %} disabled
      {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}>
      <option value>Select a fruit</option>
      <option value="apple">Apple</option>
      <option value="apricot">Apricot</option>
    </select>
  </div>
</div>

<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" id="appointment-date-label" for="appointment-date"
    >Date picker</label
  >
  <div class="usa-hint" id="appointment-date-hint">mm/dd/yyyy</div>
  {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
  <div class="usa-date-picker">
    <input
      class="usa-input {% if error_state == true %}usa-input--error{% endif %}"
      id="appointment-date"
      name="appointment-date"
      aria-labelledby="appointment-date-label"
      aria-describedby="appointment-date-hint"
      {% if disabled_state == 'disabled' %} disabled
      {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
    />
  </div>
</div>

<div class="usa-form-group {% if error_state == true %} usa-form-group--error{% endif %}">
  <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="file-input-single"
    >File input</label
  >
  {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
  <input
    id="file-input-single"
    class="usa-file-input"
    type="file"
    name="file-input-single"
    {% if disabled_state == 'disabled' %} disabled
    {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
  />
</div>

{# ! 
! Input mask breaks due to DOM structure changing. Related to: #5517.
!
! This initialization error also causes subsequent JS files to not initialize properly. 
! On this page, time picker does not initialize. Removing input-mask or the error states will allow time 
! picker to properly initialize.
!#}
<form class="usa-form">
  {% if error_state == true %}<div class="usa-form-group usa-form-group--error">{% endif %}
    <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="ssn">Input mask</label>
    <div class="usa-hint" id="ssnHint">For example, 123 45 6789</div>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <input
      id="ssn"
      inputmode="numeric"
      name="ssn"
      placeholder="___ __ ____"
      pattern="^(?!(000|666|9))\d{3} (?!00)\d{2} (?!0000)\d{4}$"
      class="usa-input usa-masked {% if error_state == true %}usa-input--error{% endif %}"
      aria-describedby="ssnHint"
      {% if disabled_state == 'disabled' %} disabled
      {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
    />
  {% if error_state == true %}</div>{% endif %}
</form>

{# * 
* Input prefix/suffix input group
* For input prefix/suffix, the usa-input--error class must be put on the usa-input-group element in order for 
* the styles to display as expected
*#}
<form class="usa-form">
  {% if error_state == true %}<div class="usa-form-group usa-form-group--error">{% endif %}
    <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="example-input-prefix">Input prefix</label>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <div class="usa-input-group {% if error_state == true %}usa-input--error{% endif %}">
      <div class="usa-input-prefix" aria-hidden="true">
        <svg aria-hidden="true" role="img" focusable="false" class="usa-icon">
          <use xlink:href="./img/sprite.svg#credit_card"></use>
        </svg>
      </div>
      <input
        id="example-input-prefix"
        class="usa-input"
        pattern="[0-9]*"
        inputmode="numeric"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      />
    </div>
  {% if error_state == true %}</div>{% endif %}
</form>

<form class="usa-form">
  {% if error_state == true %}<div class="usa-form-group usa-form-group--error">{% endif %}
    <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="example-input-suffix">Input suffix</label>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <div class="usa-input-group usa-input-group--sm {% if error_state == true %}usa-input--error{% endif %}">
      <input
        id="example-input-suffix"
        class="usa-input"
        pattern="[0-9]*"
        inputmode="numeric"
        {% if disabled_state == 'disabled' %} disabled
        {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      />
      <div class="usa-input-suffix" aria-hidden="true">lbs.</div>
    </div>
  {% if error_state == true %}</div>{% endif %}
</form>

<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <fieldset class="usa-fieldset">
    <legend class="usa-legend {% if error_state == true %}usa-label--error{% endif %}">Memorable date</legend>
    <span class="usa-hint" id="mdHint">For example: January 19 2000</span>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <div class="usa-memorable-date">
      <div class="usa-form-group usa-form-group--month usa-form-group--select">
        <label class="usa-label" for="date_of_birth_month">Month</label>
        <select
          class="usa-select {% if error_state == true %}usa-input--error{% endif %}"
          id="date_of_birth_month"
          name="date_of_birth_month"
          aria-describedby="mdHint"
          {% if disabled_state == 'disabled' %} disabled
          {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
        >
          <option value>- Select -</option>
          <option value="1">01 - January</option>
          <option value="2">02 - February</option>
          <option value="3">03 - March</option>
          <option value="4">04 - April</option>
          <option value="5">05 - May</option>
          <option value="6">06 - June</option>
          <option value="7">07 - July</option>
          <option value="8">08 - August</option>
          <option value="9">09 - September</option>
          <option value="10">10 - October</option>
          <option value="11">11 - November</option>
          <option value="12">12 - December</option>
        </select>
      </div>
      <div class="usa-form-group usa-form-group--day">
        <label class="usa-label" for="date_of_birth_day">Day</label>
        <input
          class="usa-input {% if error_state == true %}usa-input--error{% endif %}"
          aria-describedby="mdHint"
          id="date_of_birth_day"
          name="date_of_birth_day"
          maxlength="2"
          pattern="[0-9]*"
          inputmode="numeric"
          value=""
          {% if disabled_state == 'disabled' %} disabled
          {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
        />
      </div>
      <div class="usa-form-group usa-form-group--year">
        <label class="usa-label" for="date_of_birth_year">Year</label>
        <input
          class="usa-input {% if error_state == true %}usa-input--error{% endif %}"
          aria-describedby="mdHint"
          id="date_of_birth_year"
          name="date_of_birth_year"
          minlength="4"
          maxlength="4"
          pattern="[0-9]*"
          inputmode="numeric"
          value=""
          {% if disabled_state == 'disabled' %} disabled
          {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
        />
      </div>
    </div>
  </fieldset>
</div>

<form class="usa-form">
  {% if error_state == true %}<div class="usa-form-group usa-form-group--error">{% endif %}
    <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="usa-range">Range slider</label>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <input
      id="usa-range"
      class="usa-range"
      type="range"
      min="0"
      max="100"
      step="10"
      value="20"
      aria-valuemin="0"
      aria-valuemax="100"
      aria-valuenow="20"
      role="slider"
      {% if disabled_state == 'disabled' %} disabled
      {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
    />
  {% if error_state == true %}</div>{% endif %}
</form>

<form class="usa-form">
  {% if error_state == true %}<div class="usa-form-group usa-form-group--error">{% endif %}
    <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="options">Select</label>
    {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
    <select
      class="usa-select {% if error_state == true %}usa-input--error{% endif %}"
      name="options"
      id="options"
      {% if disabled_state == 'disabled' %} disabled
      {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
      >
      <option value>- Select -</option>
      <option value="value1">Option A</option>
      <option value="value2">Option B</option>
      <option value="value3">Option C</option>
    </select>
  {% if error_state == true %}</div>{% endif %}
</form>

<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" for="input-type-text">Text input</label>
  {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
  <input
    class="usa-input {% if error_state == true %}usa-input--error{% endif %}"
    id="input-type-text"
    name="input-type-text"
    type="text"
    {% if disabled_state == 'disabled' %} disabled
    {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
  >
</div>

{# !
! Due to Combo box's dynamic input element not receiving the same classes as it's select placeholder, 
! the error input classes are not set on initialization
!#}
<div class="usa-form-group {% if error_state == true %}usa-form-group--error{% endif %}">
  <label class="usa-label {% if error_state == true %}usa-label--error{% endif %}" id="appointment-time-label" for="appointment-time"
    >Time picker</label
  >
  <div class="usa-hint" id="appointment-time-hint">hh:mm</div>
  {% if error_state == true %}<span class="usa-error-message" role="alert">Helpful error message</span>{% endif %}
  <div class="usa-time-picker">
    <input
      class="usa-input {% if error_state == true %}usa-input--error{% endif %}"
      id="appointment-time"
      name="appointment-time"
      aria-describedby="appointment-time-label appointment-time-hint"
      {% if disabled_state == 'disabled' %} disabled
      {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
    />
  </div>
</div>

<button
  type="submit"
  class="usa-button margin-top-2"
  {% if disabled_state == 'disabled' %} disabled
  {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
  >Submit button</button>

<button
  type="submit"
  class="usa-button usa-button--outline margin-top-2"
  {% if disabled_state == 'disabled' %} disabled
  {% elseif disabled_state == 'aria-disabled' %} aria-disabled="true" {%- endif %}
  >Submit button - outline</button>