Skip to main content

Mutually Exclusive

When to use this component

The mutually exclusive component provides the user with a with a way of selecting multiple items or a single opposing value.

How to use this component

This component degrades gracefully if JavaScript is not available to the user. If JavaScript is unavailable it is possible for the user to select all options without inverting the selection therefore further, server-side validation should be performed.

Inputs, radios, checkboxes, date inputs, and textareas all call this macro automatically if they have their mutuallyExclusive paramater set. This will add the necessary checkbox and aria-live markup, and the classes required by the JavaScript that runs the component. Where you are combining input components such as in the duration example you must call this macro and provide the class js-exclusive-group-item to the inputs.

Examples

Checkboxes

<fieldset class="fieldset">
  <legend class="fieldset__legend">
    <h1 class="fieldset__legend-title ">What type of central heating do you have?</h1>
  </legend>
  <div class="js-mutually-exclusive mutually-exclusive">
    <p class="checkboxes__label">Select all that apply</p>
    <div class="checkboxes__items">
      <p class="checkboxes__item">
        <span class="checkbox ">
          <input type="checkbox" id="gas" class="checkbox__input js-checkbox  js-exclusive-group-item" value="gas">
          <label class="checkbox__label  " for="gas" id="gas-label">Gas
          </label>
        </span>
      </p>
      <br>
      <p class="checkboxes__item">
        <span class="checkbox ">
          <input type="checkbox" id="electric" class="checkbox__input js-checkbox  js-exclusive-group-item" value="electric">
          <label class="checkbox__label  " for="electric" id="electric-label">Electric
          </label>
        </span>
      </p>
      <br>
      <p class="checkboxes__item">
        <span class="checkbox ">
          <input type="checkbox" id="solid-fuel" class="checkbox__input js-checkbox  js-exclusive-group-item" value="solid-fuel">
          <label class="checkbox__label  " for="solid-fuel" id="solid-fuel-label">Solid fuel
          </label>
        </span>
      </p>
      <br>
      <p class="checkboxes__item">
        <span class="checkbox ">
          <input type="checkbox" id="other-fuel" class="checkbox__input js-checkbox  js-exclusive-group-item" value="other" aria-controls="other-fuel-other-wrap" aria-haspopup="true">
          <label class="checkbox__label  " for="other-fuel" id="other-fuel-label">Other
          </label>
          <span class="checkbox__other" id="other-fuel-other-wrap">
            <label class="label u-fs-s--b " for="other-fuel-textbox" id="other-fuel-textbox-label">Please specify
            </label>
            <input type="text" id="other-fuel-textbox" class="input input--text input-type__input input--w-auto  js-exclusive-group-item" name="other-fuel-answer" />
          </span>
        </span>
      </p>
    </div>
    <p class="checkboxes--mutually-exclusive__item u-mt-s">
      <span class="checkboxes__label u-fs-r--b" aria-hidden="true">Or</span>
      <span class="checkbox ">
        <input type="checkbox" id="no-central-heating" class="checkbox__input js-checkbox js-exclusive-checkbox" value="no-central-heating" data-attribute="Example attribute" data-deselect-message="Selecting this will uncheck all other checkboxes">
        <label class="checkbox__label  " for="no-central-heating" id="no-central-heating-label"><span class="u-vh">Or, </span> No central heating
        </label>
      </span>
    </p>
    <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-checkbox-adjective="deselected"></span>
  </div>
</fieldset>
Nunjucks macro options
Name Type Required Description
checkbox MutuallyExclusiveCheckbox true Configuration for the mutually exclusive checkbox
or string true Text for the “Or” label
deselectMessage string true The text the aria-live will read to warn that selecting the exclusive option will clear all other inputs
deselectGroupAdjective string true The text the aria-live will read when a field is deselected
deselectCheckboxAdjective string true The text the aria-live will read when the checkbox is deselected
error Error (ref) false Configuration for validation errors
{% from "components/checkboxes/_macro.njk" import onsCheckboxes %}
{{
    onsCheckboxes({
        "legend": "What type of central heating do you have?",
        "legendIsPageTitle": true,
        "checkboxesLabel": "Select all that apply",
        "name": "mutually-exclusive",
        "checkboxes": [
            {
                "id": "gas",
                "label": {
                    "text": "Gas"
                },
                "value": "gas"
            },
            {
                "id": "electric",
                "label": {
                    "text": "Electric"
                },
                "value": "electric"
            },
            {
                "id": "solid-fuel",
                "label": {
                    "text": "Solid fuel"
                },
                "value": "solid-fuel"
            },
            {
                "id": "other-fuel",
                "label": {
                    "text": "Other"
                },
                "value": "other",
                "other": {
                    "id": "other-fuel-textbox",
                    "name": "other-fuel-answer",
                    "label": {
                       "text": "Please specify"
                    }
                }
            }
        ],
        "mutuallyExclusive": {
            "or": "Or",
            "deselectMessage": "Selecting this will uncheck all other checkboxes",
            "deselectGroupAdjective": "deselected",
            "deselectCheckboxAdjective": "deselected",
            "checkbox": {
                "id": "no-central-heating",
                "label": {
                    "text": "No central heating"
                },
                "attributes": {
                    "data-attribute": "Example attribute"
                },
                "value": "no-central-heating"
            }
        }
    })
}}


{% macro onsMutuallyExclusive(params) %}
    {% from "components/fieldset/_macro.njk" import onsFieldset %}
    {% from "components/checkboxes/_checkbox-macro.njk" import onsCheckbox %}
    {# Resolves caller issue in jijna: https://github.com/pallets/jinja/issues/371 #}
    {% set content = caller() %}
    {% call onsFieldset({
        "id": params.id,
        "classes": params.classes,
        "legend": params.legend,
        "legendClasses": params.legendClasses,
        "description": params.description,
        "attributes": params.attributes,
        "dontWrap": params.dontWrap,
        "legendIsPageTitle": params.legendIsPageTitle,
        "error": params.error
    }) %}
        <div class="js-mutually-exclusive mutually-exclusive">
            {{ content | safe }}
            <p class="checkboxes--mutually-exclusive__item u-mt-s">
                <span class="checkboxes__label u-fs-r--b" aria-hidden="true">{{ params.or }}</span>
                {{
                    onsCheckbox({
                        "id": params.checkbox.id,
                        "name": params.checkbox.name,
                        "value": params.checkbox.value,
                        "checked": params.checkbox.checked,
                        "classes": params.checkbox.classes,
                        "attributes": params.checkbox.attributes,
                        "deselectMessage": params.deselectMessage,
                        "inputClasses": "js-exclusive-checkbox",
                        "label": {
                            "text": '<span class="u-vh">' + params.or + ', </span> ' + params.checkbox.label.text,
                            "description": params.checkbox.label.description
                        }
                    })
                }}
            </p>
            <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="{{ params.deselectGroupAdjective }}" data-checkbox-adjective="{{ params.deselectCheckboxAdjective }}"></span>
        </div>
    {% endcall %}
{% endmacro %}

Date

<fieldset id="date-mutually-exclusive" class="fieldset">
  <legend class="fieldset__legend">
    When did you leave your last paid job?
    <span class="fieldset__description ">For example, 31 3 2018</span>
  </legend>
  <div class="js-mutually-exclusive mutually-exclusive">
    <div class="field-group">
      <div class="field">
        <label class="label  " for="date-mutually-exclusive-day">Day
        </label>
        <input type="text" id="date-mutually-exclusive-day" class="input input--text input-type__input input--w-2 js-exclusive-group-item" name="day-exclusive" min="1" max="31" maxlength="2" pattern="[0-9]*" inputmode="numeric" />
      </div>
      <div class="field">
        <label class="label  " for="date-mutually-exclusive-month">Month
        </label>
        <input type="text" id="date-mutually-exclusive-month" class="input input--text input-type__input input--w-2 js-exclusive-group-item" name="month-exclusive" min="1" max="12" maxlength="2" pattern="[0-9]*" inputmode="numeric" />
      </div>
      <div class="field">
        <label class="label  " for="date-mutually-exclusive-year">Year
        </label>
        <input type="text" id="date-mutually-exclusive-year" class="input input--text input-type__input input--w-4 js-exclusive-group-item" name="year-exclusive" min="1000" max="3000" maxlength="4" pattern="[0-9]*" inputmode="numeric" />
      </div>
    </div>
    <p class="checkboxes--mutually-exclusive__item u-mt-s">
      <span class="checkboxes__label u-fs-r--b" aria-hidden="true">Or</span>
      <span class="checkbox ">
        <input type="checkbox" id="date-exclusive-checkbox" class="checkbox__input js-checkbox js-exclusive-checkbox" value="no-paid-job" name="no-paid-job" data-deselect-message="Selecting this will clear the date if one has been inputted">
        <label class="checkbox__label  " for="date-exclusive-checkbox" id="date-exclusive-checkbox-label"><span class="u-vh">Or, </span> I have never had a paid job
        </label>
      </span>
    </p>
    <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="cleared" data-checkbox-adjective="deselected"></span>
  </div>
</fieldset>
Nunjucks macro options
Name Type Required Description
checkbox MutuallyExclusiveCheckbox true Configuration for the mutually exclusive checkbox
or string true Text for the “Or” label
deselectMessage string true The text the aria-live will read to warn that selecting the exclusive option will clear all other inputs
deselectGroupAdjective string true The text the aria-live will read when a field is deselected
deselectCheckboxAdjective string true The text the aria-live will read when the checkbox is deselected
error Error (ref) false Configuration for validation errors
{% from "components/date-input/_macro.njk" import onsDateInput %}
{{
    onsDateInput({
        "id": "date-mutually-exclusive",
        "legend": "When did you leave your last paid job?",
        "description": "For example, 31 3 2018",
        "day": {
            "label": {
                "text": "Day"
            },
            "name": "day-exclusive"
        },
        "month": {
            "label": {
                "text": "Month"
            },
            "name": "month-exclusive"
        },
        "year": {
            "label": {
                "text": "Year"
            },
            "name": "year-exclusive"
        },
        "mutuallyExclusive": {
            "or": "Or",
            "deselectMessage": "Selecting this will clear the date if one has been inputted",
            "deselectGroupAdjective": "cleared",
            "deselectCheckboxAdjective": "deselected",
            "checkbox": {
                "id": "date-exclusive-checkbox",
                "name": "no-paid-job",
                "value": "no-paid-job",
                "label": {
                    "text": "I have never had a paid job"
                }
            }
        }
    })
}}


{% macro onsMutuallyExclusive(params) %}
    {% from "components/fieldset/_macro.njk" import onsFieldset %}
    {% from "components/checkboxes/_checkbox-macro.njk" import onsCheckbox %}
    {# Resolves caller issue in jijna: https://github.com/pallets/jinja/issues/371 #}
    {% set content = caller() %}
    {% call onsFieldset({
        "id": params.id,
        "classes": params.classes,
        "legend": params.legend,
        "legendClasses": params.legendClasses,
        "description": params.description,
        "attributes": params.attributes,
        "dontWrap": params.dontWrap,
        "legendIsPageTitle": params.legendIsPageTitle,
        "error": params.error
    }) %}
        <div class="js-mutually-exclusive mutually-exclusive">
            {{ content | safe }}
            <p class="checkboxes--mutually-exclusive__item u-mt-s">
                <span class="checkboxes__label u-fs-r--b" aria-hidden="true">{{ params.or }}</span>
                {{
                    onsCheckbox({
                        "id": params.checkbox.id,
                        "name": params.checkbox.name,
                        "value": params.checkbox.value,
                        "checked": params.checkbox.checked,
                        "classes": params.checkbox.classes,
                        "attributes": params.checkbox.attributes,
                        "deselectMessage": params.deselectMessage,
                        "inputClasses": "js-exclusive-checkbox",
                        "label": {
                            "text": '<span class="u-vh">' + params.or + ', </span> ' + params.checkbox.label.text,
                            "description": params.checkbox.label.description
                        }
                    })
                }}
            </p>
            <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="{{ params.deselectGroupAdjective }}" data-checkbox-adjective="{{ params.deselectCheckboxAdjective }}"></span>
        </div>
    {% endcall %}
{% endmacro %}

Textarea

<fieldset class="fieldset">
  <legend class="fieldset__legend">
  </legend>
  <div class="js-mutually-exclusive mutually-exclusive">
    <div class="field">
      <label class="label  " for="feedback">Why did you leave your last job?
      </label>
      <textarea id="feedback" class="input input--textarea  js-char-limit-input js-exclusive-group-item input--w-30" name="feedback" rows="8" maxlength="200" data-char-limit-ref="feedback-lim-remaining" aria-describedby="feedback-lim-remaining"></textarea>
      <span id="feedback-lim-remaining" class="input__limit u-fs-s--b u-d-no u-mt-xs" data-charcount-singular="You have {x} character remaining" data-charcount-plural="You have {x} characters remaining" data-charcount-limit-singular="" data-charcount-limit-plural="">
      </span>
    </div>
    <p class="checkboxes--mutually-exclusive__item u-mt-s">
      <span class="checkboxes__label u-fs-r--b" aria-hidden="true">Or</span>
      <span class="checkbox ">
        <input type="checkbox" id="feedback-checkbox" class="checkbox__input js-checkbox js-exclusive-checkbox" value="no-feedback" name="no-feedback" data-deselect-message="Selecting this will clear your feedback">
        <label class="checkbox__label  " for="feedback-checkbox" id="feedback-checkbox-label"><span class="u-vh">Or, </span> I don't want to provide feedback
        </label>
      </span>
    </p>
    <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="cleared" data-checkbox-adjective="deselected"></span>
  </div>
</fieldset>
Nunjucks macro options
Name Type Required Description
checkbox MutuallyExclusiveCheckbox true Configuration for the mutually exclusive checkbox
or string true Text for the “Or” label
deselectMessage string true The text the aria-live will read to warn that selecting the exclusive option will clear all other inputs
deselectGroupAdjective string true The text the aria-live will read when a field is deselected
deselectCheckboxAdjective string true The text the aria-live will read when the checkbox is deselected
error Error (ref) false Configuration for validation errors
{% from "components/textarea/_macro.njk" import onsTextarea %}
{{
    onsTextarea({
        "id": "feedback",
        "name": "feedback",
        "classes": "input--w-30",
        "label": {
            "text": "Why did you leave your last job?"
        },
        "charCheckLimit": {
            "limit": 200,
            "charCountSingular": "You have {x} character remaining",
            "charCountPlural": "You have {x} characters remaining"
        },
        "mutuallyExclusive": {
            "or": "Or",
            "deselectMessage": "Selecting this will clear your feedback",
            "deselectGroupAdjective": "cleared",
            "deselectCheckboxAdjective": "deselected",
            "checkbox": {
                "id": "feedback-checkbox",
                "name": "no-feedback",
                "value": "no-feedback",
                "label": {
                    "text": "I don't want to provide feedback"
                }
            }
        }
    })
}}


{% macro onsMutuallyExclusive(params) %}
    {% from "components/fieldset/_macro.njk" import onsFieldset %}
    {% from "components/checkboxes/_checkbox-macro.njk" import onsCheckbox %}
    {# Resolves caller issue in jijna: https://github.com/pallets/jinja/issues/371 #}
    {% set content = caller() %}
    {% call onsFieldset({
        "id": params.id,
        "classes": params.classes,
        "legend": params.legend,
        "legendClasses": params.legendClasses,
        "description": params.description,
        "attributes": params.attributes,
        "dontWrap": params.dontWrap,
        "legendIsPageTitle": params.legendIsPageTitle,
        "error": params.error
    }) %}
        <div class="js-mutually-exclusive mutually-exclusive">
            {{ content | safe }}
            <p class="checkboxes--mutually-exclusive__item u-mt-s">
                <span class="checkboxes__label u-fs-r--b" aria-hidden="true">{{ params.or }}</span>
                {{
                    onsCheckbox({
                        "id": params.checkbox.id,
                        "name": params.checkbox.name,
                        "value": params.checkbox.value,
                        "checked": params.checkbox.checked,
                        "classes": params.checkbox.classes,
                        "attributes": params.checkbox.attributes,
                        "deselectMessage": params.deselectMessage,
                        "inputClasses": "js-exclusive-checkbox",
                        "label": {
                            "text": '<span class="u-vh">' + params.or + ', </span> ' + params.checkbox.label.text,
                            "description": params.checkbox.label.description
                        }
                    })
                }}
            </p>
            <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="{{ params.deselectGroupAdjective }}" data-checkbox-adjective="{{ params.deselectCheckboxAdjective }}"></span>
        </div>
    {% endcall %}
{% endmacro %}

Email

<fieldset class="fieldset">
  <legend class="fieldset__legend undefined js-input-legend">
  </legend>
  <div class="js-mutually-exclusive mutually-exclusive">
    <label class="label  " for="email">Enter an email
    </label>
    <input type="email" id="email" class="input input--text input-type__input  js-exclusive-group-item" />
    <p class="checkboxes--mutually-exclusive__item u-mt-s">
      <span class="checkboxes__label u-fs-r--b" aria-hidden="true">Or</span>
      <span class="checkbox ">
        <input type="checkbox" id="email-checkbox" class="checkbox__input js-checkbox js-exclusive-checkbox" value="no-email" name="no-email" data-deselect-message="Selecting this will clear your email">
        <label class="checkbox__label  " for="email-checkbox" id="email-checkbox-label"><span class="u-vh">Or, </span> I don't want to receive a confirmation email
        </label>
      </span>
    </p>
    <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="cleared" data-checkbox-adjective="deselected"></span>
  </div>
</fieldset>
Nunjucks macro options
Name Type Required Description
checkbox MutuallyExclusiveCheckbox true Configuration for the mutually exclusive checkbox
or string true Text for the “Or” label
deselectMessage string true The text the aria-live will read to warn that selecting the exclusive option will clear all other inputs
deselectGroupAdjective string true The text the aria-live will read when a field is deselected
deselectCheckboxAdjective string true The text the aria-live will read when the checkbox is deselected
error Error (ref) false Configuration for validation errors
{% from "components/input/_macro.njk" import onsInput %}
{{
    onsInput({
        "id": "email",
        "type": "email",
        "label": {
            "text": "Enter an email"
        },
        "mutuallyExclusive": {
            "or": "Or",
            "deselectMessage": "Selecting this will clear your email",
            "deselectGroupAdjective": "cleared",
            "deselectCheckboxAdjective": "deselected",
            "checkbox": {
                "id": "email-checkbox",
                "name": "no-email",
                "value": "no-email",
                "label": {
                    "text": "I don't want to receive a confirmation email"
                }
            }
        }
    })
}}


{% macro onsMutuallyExclusive(params) %}
    {% from "components/fieldset/_macro.njk" import onsFieldset %}
    {% from "components/checkboxes/_checkbox-macro.njk" import onsCheckbox %}
    {# Resolves caller issue in jijna: https://github.com/pallets/jinja/issues/371 #}
    {% set content = caller() %}
    {% call onsFieldset({
        "id": params.id,
        "classes": params.classes,
        "legend": params.legend,
        "legendClasses": params.legendClasses,
        "description": params.description,
        "attributes": params.attributes,
        "dontWrap": params.dontWrap,
        "legendIsPageTitle": params.legendIsPageTitle,
        "error": params.error
    }) %}
        <div class="js-mutually-exclusive mutually-exclusive">
            {{ content | safe }}
            <p class="checkboxes--mutually-exclusive__item u-mt-s">
                <span class="checkboxes__label u-fs-r--b" aria-hidden="true">{{ params.or }}</span>
                {{
                    onsCheckbox({
                        "id": params.checkbox.id,
                        "name": params.checkbox.name,
                        "value": params.checkbox.value,
                        "checked": params.checkbox.checked,
                        "classes": params.checkbox.classes,
                        "attributes": params.checkbox.attributes,
                        "deselectMessage": params.deselectMessage,
                        "inputClasses": "js-exclusive-checkbox",
                        "label": {
                            "text": '<span class="u-vh">' + params.or + ', </span> ' + params.checkbox.label.text,
                            "description": params.checkbox.label.description
                        }
                    })
                }}
            </p>
            <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="{{ params.deselectGroupAdjective }}" data-checkbox-adjective="{{ params.deselectCheckboxAdjective }}"></span>
        </div>
    {% endcall %}
{% endmacro %}

Number/Currency

<fieldset class="fieldset">
  <legend class="fieldset__legend undefined js-input-legend">
  </legend>
  <div class="js-mutually-exclusive mutually-exclusive">
    <label class="label  " for="currency">What is your annual income before tax?
    </label>
    <span class="input-type input-type--prefix">
      <span class="input-type__inner">
        <input type="text" id="currency" class="input input--text input-type__input input--w-5 js-exclusive-group-item" title="Pounds (GBP)" pattern="[0-9]*" inputmode="numeric" min />
        <abbr class="input-type__type js-input-abbr" aria-hidden="true" title="Pounds (GBP)">£</abbr>
      </span>
    </span>
    <p class="checkboxes--mutually-exclusive__item u-mt-s">
      <span class="checkboxes__label u-fs-r--b" aria-hidden="true">Or</span>
      <span class="checkbox ">
        <input type="checkbox" id="currency-checkbox" class="checkbox__input js-checkbox js-exclusive-checkbox" value="no-currency" name="no-currency" data-deselect-message="Selecting this will clear your inputted annual income">
        <label class="checkbox__label  " for="currency-checkbox" id="currency-checkbox-label"><span class="u-vh">Or, </span> I prefer not to say
        </label>
      </span>
    </p>
    <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="cleared" data-checkbox-adjective="deselected"></span>
  </div>
</fieldset>
Nunjucks macro options
Name Type Required Description
checkbox MutuallyExclusiveCheckbox true Configuration for the mutually exclusive checkbox
or string true Text for the “Or” label
deselectMessage string true The text the aria-live will read to warn that selecting the exclusive option will clear all other inputs
deselectGroupAdjective string true The text the aria-live will read when a field is deselected
deselectCheckboxAdjective string true The text the aria-live will read when the checkbox is deselected
error Error (ref) false Configuration for validation errors
{% from "components/input/_macro.njk" import onsInput %}
{{
    onsInput({
        "id": "currency",
        "type": "number",
        "classes": "input--w-5",
        "attributes": {
            "min": 0
        },
        "label": {
            "text": "What is your annual income before tax?"
        },
        "prefix": {
            "title": "Pounds (GBP)",
            "text": "£"
        },
        "mutuallyExclusive": {
            "or": "Or",
            "deselectMessage": "Selecting this will clear your inputted annual income",
            "deselectGroupAdjective": "cleared",
            "deselectCheckboxAdjective": "deselected",
            "checkbox": {
                "id": "currency-checkbox",
                "name": "no-currency",
                "value": "no-currency",
                "label": {
                    "text": "I prefer not to say"
                }
            }
        }
    })
}}


{% macro onsMutuallyExclusive(params) %}
    {% from "components/fieldset/_macro.njk" import onsFieldset %}
    {% from "components/checkboxes/_checkbox-macro.njk" import onsCheckbox %}
    {# Resolves caller issue in jijna: https://github.com/pallets/jinja/issues/371 #}
    {% set content = caller() %}
    {% call onsFieldset({
        "id": params.id,
        "classes": params.classes,
        "legend": params.legend,
        "legendClasses": params.legendClasses,
        "description": params.description,
        "attributes": params.attributes,
        "dontWrap": params.dontWrap,
        "legendIsPageTitle": params.legendIsPageTitle,
        "error": params.error
    }) %}
        <div class="js-mutually-exclusive mutually-exclusive">
            {{ content | safe }}
            <p class="checkboxes--mutually-exclusive__item u-mt-s">
                <span class="checkboxes__label u-fs-r--b" aria-hidden="true">{{ params.or }}</span>
                {{
                    onsCheckbox({
                        "id": params.checkbox.id,
                        "name": params.checkbox.name,
                        "value": params.checkbox.value,
                        "checked": params.checkbox.checked,
                        "classes": params.checkbox.classes,
                        "attributes": params.checkbox.attributes,
                        "deselectMessage": params.deselectMessage,
                        "inputClasses": "js-exclusive-checkbox",
                        "label": {
                            "text": '<span class="u-vh">' + params.or + ', </span> ' + params.checkbox.label.text,
                            "description": params.checkbox.label.description
                        }
                    })
                }}
            </p>
            <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="{{ params.deselectGroupAdjective }}" data-checkbox-adjective="{{ params.deselectCheckboxAdjective }}"></span>
        </div>
    {% endcall %}
{% endmacro %}

Duration

<div class="question">
  <fieldset class="fieldset">
    <legend class="fieldset__legend">
      <h1 class="fieldset__legend-title ">How long have you lived at this address?</h1>
      <span class="fieldset__description fieldset__description--title">
        <p>If you have lived at this address for less than a year then enter 0 into the year input.</p>
      </span>
    </legend>
    <div class="input-items">
      <div class="js-mutually-exclusive mutually-exclusive">
        <div class="field-group">
          <div class="field">
            <span class="input-type">
              <span class="input-type__inner">
                <input type="text" id="address-duration-years" class="input input--text input-type__input input--w-2 js-exclusive-group-item" title="Years" name="address-duration-years" pattern="[0-9]*" inputmode="numeric" min max="100" />
                <abbr class="input-type__type js-input-abbr" aria-hidden="true" title="Years">Years</abbr>
              </span>
            </span>
          </div>
          <div class="field">
            <span class="input-type">
              <span class="input-type__inner">
                <input type="text" id="address-duration-months" class="input input--text input-type__input input--w-2 js-exclusive-group-item" title="Months" name="address-duration-months" pattern="[0-9]*" inputmode="numeric" min max="11" />
                <abbr class="input-type__type js-input-abbr" aria-hidden="true" title="Months">Months</abbr>
              </span>
            </span>
          </div>
        </div>
        <p class="checkboxes--mutually-exclusive__item u-mt-s">
          <span class="checkboxes__label u-fs-r--b" aria-hidden="true">Or</span>
          <span class="checkbox ">
            <input type="checkbox" id="duration-exclusive-checkbox" class="checkbox__input js-checkbox js-exclusive-checkbox" value="no-duration" name="no-duration" data-deselect-message="Selecting this will clear the date if one has been inputted">
            <label class="checkbox__label  " for="duration-exclusive-checkbox" id="duration-exclusive-checkbox-label"><span class="u-vh">Or, </span> I have not moved in to this address yet
            </label>
          </span>
        </p>
        <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="cleared" data-checkbox-adjective="deselected"></span>
      </div>
    </div>
  </fieldset>
</div>
Nunjucks macro options
Name Type Required Description
checkbox MutuallyExclusiveCheckbox true Configuration for the mutually exclusive checkbox
or string true Text for the “Or” label
deselectMessage string true The text the aria-live will read to warn that selecting the exclusive option will clear all other inputs
deselectGroupAdjective string true The text the aria-live will read when a field is deselected
deselectCheckboxAdjective string true The text the aria-live will read when the checkbox is deselected
error Error (ref) false Configuration for validation errors
{% from "components/question/_macro.njk" import onsQuestion %}
{% from "components/duration/_macro.njk" import onsDuration %}
{% call onsQuestion({
    "title": "How long have you lived at this address?",
    "description": "<p>If you have lived at this address for less than a year then enter 0 into the year input.</p>",
    "legendIsPageTitle": true
}) %}
    {{ onsDuration({
        "id": "address-duration",
        "dontWrap": true,
        "field1": {
            "id": "address-duration-years",
            "name": "address-duration-years",
            "label": "Years",
            "attributes": {
                "min": 0,
                "max": 100
            }
        },
        "field2": {
            "id": "address-duration-months",
            "name": "address-duration-months",
            "label": "Months",
            "attributes": {
                "min": 0,
                "max": 11
            }
        },
        "mutuallyExclusive": {
            "or": "Or",
            "deselectMessage": "Selecting this will clear the date if one has been inputted",
            "deselectGroupAdjective": "cleared",
            "deselectCheckboxAdjective": "deselected",
            "checkbox": {
                "id": "duration-exclusive-checkbox",
                "name": "no-duration",
                "value": "no-duration",
                "label": {
                    "text": "I have not moved in to this address yet"
                }
            }
        }
    }) }}
{% endcall %}


{% macro onsMutuallyExclusive(params) %}
    {% from "components/fieldset/_macro.njk" import onsFieldset %}
    {% from "components/checkboxes/_checkbox-macro.njk" import onsCheckbox %}
    {# Resolves caller issue in jijna: https://github.com/pallets/jinja/issues/371 #}
    {% set content = caller() %}
    {% call onsFieldset({
        "id": params.id,
        "classes": params.classes,
        "legend": params.legend,
        "legendClasses": params.legendClasses,
        "description": params.description,
        "attributes": params.attributes,
        "dontWrap": params.dontWrap,
        "legendIsPageTitle": params.legendIsPageTitle,
        "error": params.error
    }) %}
        <div class="js-mutually-exclusive mutually-exclusive">
            {{ content | safe }}
            <p class="checkboxes--mutually-exclusive__item u-mt-s">
                <span class="checkboxes__label u-fs-r--b" aria-hidden="true">{{ params.or }}</span>
                {{
                    onsCheckbox({
                        "id": params.checkbox.id,
                        "name": params.checkbox.name,
                        "value": params.checkbox.value,
                        "checked": params.checkbox.checked,
                        "classes": params.checkbox.classes,
                        "attributes": params.checkbox.attributes,
                        "deselectMessage": params.deselectMessage,
                        "inputClasses": "js-exclusive-checkbox",
                        "label": {
                            "text": '<span class="u-vh">' + params.or + ', </span> ' + params.checkbox.label.text,
                            "description": params.checkbox.label.description
                        }
                    })
                }}
            </p>
            <span class="js-exclusive-alert u-vh" role="alert" aria-live="polite" data-group-adjective="{{ params.deselectGroupAdjective }}" data-checkbox-adjective="{{ params.deselectCheckboxAdjective }}"></span>
        </div>
    {% endcall %}
{% endmacro %}

Research on this component

If you have conducted any user research using this pattern, please feed back your findings via the Design System forum 

Design System forum

Discuss ‘Mutually Exclusive’ on GitHub