Skip to main content

Select

These should never be used for short lists of items that could be better served by using radio options.

Use with caution

GDS advise against using drop-down select boxes as they have poor accessibility and can be cumbersome to use on a mobile device.

They hide the choices and can confuse users as they may not understand what they’re being asked before they see the answers by interacting with the element.

Where large lists are involved, some users may be unaware that they can scroll through the entire list to find the appropriate answer.

Because the expanded list cannot be styled, this may cause usability issues where the drop-down itself may be difficult to read for users with visual impairments.

<div class="ons-field">
  <label class="ons-label  " for="select">Question topic
  </label>
  <select id="select" name="select" class="ons-input ons-input--select">
    <option value="" selected disabled>Select an option</option>
    <option value="general">General</option>
    <option value="people-who-live-here">People who live here</option>
    <option value="visitors">Visitors</option>
    <option value="household-accommodation">Household and accommodation</option>
    <option value="personal-details">Personal details</option>
    <option value="health">Health</option>
    <option value="qualifications">Qualifications</option>
    <option value="employment">Employment</option>
  </select>
</div>
{% from "components/select/_macro.njk" import onsSelect %}
{{
    onsSelect({
        "id": "select",
        "name": "select",
        "label": {
            "text": "Question topic"
        },
        "options": [
            {
                "value": "",
                "text": "Select an option",
                "disabled": true,
                "selected": true
            },
            {
                "value": "general",
                "text": "General"
            },
            {
                "value": "people-who-live-here",
                "text": "People who live here"
            },
            {
                "value": "visitors",
                "text": "Visitors"
            },
            {
                "value": "household-accommodation",
                "text": "Household and accommodation"
            },
            {
                "value": "personal-details",
                "text": "Personal details"
            },
            {
                "value": "health",
                "text": "Health"
            },
            {
                "value": "qualifications",
                "text": "Qualifications"
            },
            {
                "value": "employment",
                "text": "Employment"
            }
        ]
    })
}}
Name Type Required Description
id string true The id of the select. This will also be added to the label if a label is specified
classes string false Classes to add to the select.
name string false The name of the select
value string | number false The value of the select. Helpful for setting the preselected value
attributes object false HTML attributes (for example, data attributes) to add to the select
label Label (ref) false Settings for the select label. for will automatically be set to match the select id
options Array<SelectOption> true An array of options for the select
fieldId string false Id for the field
fieldClasses string false Classes for the field
dontWrap boolean false Prevents the select from being wrapped in a field component
error Error (ref) false Configuration for validation errors

SelectOption

Name Type Required Description
text string true The text for the option
value string | number false The value for the option. If not specified the value will be equal to text
selected boolean false Whether the option is selected. Only one option should have this set
disabled boolean false Whether the option should be disabled. Useful for creating a default option that should not be reselectable, for example, “Please select”
{% macro onsSelect(params) %}
    {% from "components/field/_macro.njk" import onsField %}
    {% from "components/label/_macro.njk" import onsLabel %}

    {% call onsField({
        "id": params.fieldId,
        "classes": params.fieldClases,
        "legendClasses": params.legendClasses,
        "dontWrap": params.dontWrap,
        "legendIsQuestionTitle": params.legendIsQuestionTitle,
        "error": params.error
    }) %}
        {{
            onsLabel({
                "for": params.id,
                "text": params.label.text,
                "description": params.label.description,
                "classes": params.label.classes
            })
        }}
        <select
            id="{{ params.id }}"
            name="{{ params.name }}"
            class="ons-input ons-input--select{% if params.classes %} {{ params.classes }}{% endif %}{% if params.select and params.select.error %} ons-input--error{% endif %}"
            {% if params.value is defined and params.value %}value="{{ params.value}}" {% endif %}
            {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ attribute }}{% if value is defined and value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
        >
            {% for option in params.options %}
            <option value="{{ option.value | default(option.text) }}"
                {% if option.id is defined and option.id %}"id"="{{ option.id }}" {% endif %}
                {% if option.selected is defined and option.selected %}selected {% endif %}
                {% if option.disabled is defined and option.disabled %}disabled {% endif %}
                {% if params.attributes is defined and params.attributes %}{% for attribute, value in option.attributes %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
            >
                {{- option.text -}}
            </option>
            {% endfor %}
        </select>
    {% endcall %}
{% endmacro %}

Variants

Wide

<div class="ons-field">
  <label class="ons-label  " for="select-wide">Question topic
  </label>
  <select id="select-wide" name="select" class="ons-input ons-input--select ons-input--block">
    <option value="" selected disabled>Select an option</option>
    <option value="general">General</option>
    <option value="people-who-live-here">People who live here</option>
    <option value="visitors">Visitors</option>
    <option value="household-accommodation">Household and accommodation</option>
    <option value="personal-details">Personal details</option>
    <option value="health">Health</option>
    <option value="qualifications">Qualifications</option>
    <option value="employment">Employment</option>
    <option value="gdp">Gross Domestic Product figures for year ending April 2018</option>
  </select>
</div>
{% from "components/select/_macro.njk" import onsSelect %}
{{
    onsSelect({
        "id": "select-wide",
        "name": "select",
        "classes": "ons-input--block",
        "label": {
            "text": "Question topic"
        },
        "options": [
            {
                "value": "",
                "text": "Select an option",
                "disabled": true,
                "selected": true
            },
            {
                "value": "general",
                "text": "General"
            },
            {
                "value": "people-who-live-here",
                "text": "People who live here"
            },
            {
                "value": "visitors",
                "text": "Visitors"
            },
            {
                "value": "household-accommodation",
                "text": "Household and accommodation"
            },
            {
                "value": "personal-details",
                "text": "Personal details"
            },
            {
                "value": "health",
                "text": "Health"
            },
            {
                "value": "qualifications",
                "text": "Qualifications"
            },
            {
                "value": "employment",
                "text": "Employment"
            },
            {
                "value": "gdp",
                "text": "Gross Domestic Product figures for year ending April 2018"
            }
        ]
    })
}}
Name Type Required Description
id string true The id of the select. This will also be added to the label if a label is specified
classes string false Classes to add to the select.
name string false The name of the select
value string | number false The value of the select. Helpful for setting the preselected value
attributes object false HTML attributes (for example, data attributes) to add to the select
label Label (ref) false Settings for the select label. for will automatically be set to match the select id
options Array<SelectOption> true An array of options for the select
fieldId string false Id for the field
fieldClasses string false Classes for the field
dontWrap boolean false Prevents the select from being wrapped in a field component
error Error (ref) false Configuration for validation errors

SelectOption

Name Type Required Description
text string true The text for the option
value string | number false The value for the option. If not specified the value will be equal to text
selected boolean false Whether the option is selected. Only one option should have this set
disabled boolean false Whether the option should be disabled. Useful for creating a default option that should not be reselectable, for example, “Please select”
{% macro onsSelect(params) %}
    {% from "components/field/_macro.njk" import onsField %}
    {% from "components/label/_macro.njk" import onsLabel %}

    {% call onsField({
        "id": params.fieldId,
        "classes": params.fieldClases,
        "legendClasses": params.legendClasses,
        "dontWrap": params.dontWrap,
        "legendIsQuestionTitle": params.legendIsQuestionTitle,
        "error": params.error
    }) %}
        {{
            onsLabel({
                "for": params.id,
                "text": params.label.text,
                "description": params.label.description,
                "classes": params.label.classes
            })
        }}
        <select
            id="{{ params.id }}"
            name="{{ params.name }}"
            class="ons-input ons-input--select{% if params.classes %} {{ params.classes }}{% endif %}{% if params.select and params.select.error %} ons-input--error{% endif %}"
            {% if params.value is defined and params.value %}value="{{ params.value}}" {% endif %}
            {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ attribute }}{% if value is defined and value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
        >
            {% for option in params.options %}
            <option value="{{ option.value | default(option.text) }}"
                {% if option.id is defined and option.id %}"id"="{{ option.id }}" {% endif %}
                {% if option.selected is defined and option.selected %}selected {% endif %}
                {% if option.disabled is defined and option.disabled %}disabled {% endif %}
                {% if params.attributes is defined and params.attributes %}{% for attribute, value in option.attributes %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
            >
                {{- option.text -}}
            </option>
            {% endfor %}
        </select>
    {% endcall %}
{% endmacro %}

How to check drop-down selection

You should check that users have selected one of the drop-down options and show an error message if they have not.

Error messages

Use the correct errors pattern and show the error details above the drop-down.

<div class="ons-panel ons-panel--error ons-panel--no-title ons-u-mb-s" id="select-error">
  <span class="ons-u-vh">Error: </span>
  <div class="ons-panel__body">
    <p class="ons-panel__error">
      <strong>Select a question topic</strong>
    </p>
    <div class="ons-field">
      <label class="ons-label  " for="select">Question topic
      </label>
      <select id="select" name="select" class="ons-input ons-input--select">
        <option value="" selected disabled>Select an option</option>
        <option value="general">General</option>
        <option value="people-who-live-here">People who live here</option>
        <option value="visitors">Visitors</option>
        <option value="household-accommodation">Household and accommodation</option>
        <option value="personal-details">Personal details</option>
        <option value="health">Health</option>
        <option value="qualifications">Qualifications</option>
        <option value="employment">Employment</option>
      </select>
    </div>
  </div>
</div>
{% from "components/select/_macro.njk" import onsSelect %}

{{
    onsSelect({
        "id": "select",
        "name": "select",
        "label": {
            "text": "Question topic"
        },
        "label": {
            "text": "Question topic"
        },
        "options": [
            {
                "value": "",
                "text": "Select an option",
                "disabled": true,
                "selected": true
            },
            {
                "value": "general",
                "text": "General"
            },
            {
                "value": "people-who-live-here",
                "text": "People who live here"
            },
            {
                "value": "visitors",
                "text": "Visitors"
            },
            {
                "value": "household-accommodation",
                "text": "Household and accommodation"
            },
            {
                "value": "personal-details",
                "text": "Personal details"
            },
            {
                "value": "health",
                "text": "Health"
            },
            {
                "value": "qualifications",
                "text": "Qualifications"
            },
            {
                "value": "employment",
                "text": "Employment"
            }
        ],
        "error": {
            "id": "select-error",
            "text": "Select a question topic",
            "dsExample": isPatternLib
        }
    })
}}
Name Type Required Description
id string true The id of the select. This will also be added to the label if a label is specified
classes string false Classes to add to the select.
name string false The name of the select
value string | number false The value of the select. Helpful for setting the preselected value
attributes object false HTML attributes (for example, data attributes) to add to the select
label Label (ref) false Settings for the select label. for will automatically be set to match the select id
options Array<SelectOption> true An array of options for the select
fieldId string false Id for the field
fieldClasses string false Classes for the field
dontWrap boolean false Prevents the select from being wrapped in a field component
error Error (ref) false Configuration for validation errors

SelectOption

Name Type Required Description
text string true The text for the option
value string | number false The value for the option. If not specified the value will be equal to text
selected boolean false Whether the option is selected. Only one option should have this set
disabled boolean false Whether the option should be disabled. Useful for creating a default option that should not be reselectable, for example, “Please select”
{% macro onsSelect(params) %}
    {% from "components/field/_macro.njk" import onsField %}
    {% from "components/label/_macro.njk" import onsLabel %}

    {% call onsField({
        "id": params.fieldId,
        "classes": params.fieldClases,
        "legendClasses": params.legendClasses,
        "dontWrap": params.dontWrap,
        "legendIsQuestionTitle": params.legendIsQuestionTitle,
        "error": params.error
    }) %}
        {{
            onsLabel({
                "for": params.id,
                "text": params.label.text,
                "description": params.label.description,
                "classes": params.label.classes
            })
        }}
        <select
            id="{{ params.id }}"
            name="{{ params.name }}"
            class="ons-input ons-input--select{% if params.classes %} {{ params.classes }}{% endif %}{% if params.select and params.select.error %} ons-input--error{% endif %}"
            {% if params.value is defined and params.value %}value="{{ params.value}}" {% endif %}
            {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ attribute }}{% if value is defined and value %}="{{ value }}"{% endif %} {% endfor %}{% endif %}
        >
            {% for option in params.options %}
            <option value="{{ option.value | default(option.text) }}"
                {% if option.id is defined and option.id %}"id"="{{ option.id }}" {% endif %}
                {% if option.selected is defined and option.selected %}selected {% endif %}
                {% if option.disabled is defined and option.disabled %}disabled {% endif %}
                {% if params.attributes is defined and params.attributes %}{% for attribute, value in option.attributes %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
            >
                {{- option.text -}}
            </option>
            {% endfor %}
        </select>
    {% endcall %}
{% endmacro %}

If a drop-down option has not been selected

Use “Select [whatever topic the drop-down is asking for]”.
For example, “Select a question topic”.

Help improve this component

Let us know how we could improve this component or share your user research findings. Discuss the ‘Select’ component on GitHub