<select>: Елемент вибору HTML

{{HTMLSidebar}}

Елемент HTML <select> (вибір) представляє контрольний елемент, що надає меню з варіантів вибору.

Спробуйте його в дії

Приклад вище показує типове використання <select>. Елемент отримує атрибут id, котрий дає змогу пов'язати його з елементом <label> для потреб доступності, а також атрибут name, котрий представляє ім'я відповідної порції даних при поданні форми на сервер. Кожен варіант меню описується елементом <option>, дочірнім щодо <select>.

Кожен елемент <option> повинен мати атрибут value, що містить значення, котре буде подано на сервер, якщо відповідний варіант – обраний. Якщо атрибута value немає, то усталеним значенням є текст всередині елемента. Щоб елемент option був обраним при першому завантаженні сторінки, слід вказати атрибут selected елемента <option>.

Елемент <select> має певні унікальні атрибути для контролю над собою, наприклад, multiple для задання можливості (чи неможливості) вибору кількох варіантів та size з кількістю варіантів, котру можна обрати водночас. Також він приймає більшість звичних атрибутів полів вводу, наприклад, required, disabled, autofocus тощо.

Можна вкладати елементи <option> в елементи <optgroup>, щоб створити розмежовані групи варіантів всередині спадного списку. Також можна додавати елементи <hr>, щоб утворювати розділювачі, що служать візуальними розривами між варіантами.

Інші приклади використання доступні за посиланням: Нативні віджети форми: Вміст спадного списку.

Атрибути

Цей елемент приймає глобальні атрибути.

autocomplete (автозаповнення)

Рядок, що дає підказку функціональності автозаповнення користувацького агента. Повний список значень та деталей про те, як використовувати автозаповнення, доступний за посиланням: HTML-атрибут автозаповнення.

autofocus (автофокус)

Цей булів атрибут дає змогу вказати, що контрольний елемент повинен отримати фокус введення, коли сторінка завантажилась. Лише один елемент форми в документі може мати атрибут autofocus.

disabled (вимкнений)

Цей булів атрибут показує, що користувач не може взаємодіяти з контрольним елементом. Якщо цей атрибут не вказаний, то контрольний елемент успадковує це налаштування від контейнерного елемента, наприклад, <fieldset>; якщо немає контейнерного елемента з атрибутом disabled, то контрольний елемент є увімкненим.

form (форма)

Елемент <form>, з котрим елемент <select> пов'язаний (його форма-власник). Значення цього атрибута мусить відповідати значенню атрибута id елемента <form> в тому самому документі. (Якщо цей атрибут не вказаний, то <select> пов'язується з елементом <form>, котрий є його предком, якщо такий предок є.)

Цей атрибут дає змогу пов'язувати елементи <select> із формами будь-де в документі, не поміщаючи їх у відповідний <form>. Також така поведінка змушує нехтувати батьківським елементом <form>.

multiple (декілька)

Цей булів атрибут показує, що зі списку можуть бути обрані кілька варіантів. Якщо він не вказаний, то лише один варіант може бути обраним водночас. Коли вказаний multiple, більшість браузерів замість однорядкового спадного списку показують віконце списку з прокруткою.

name (ім'я)

Цей атрибут використовується, щоб вказати ім'я контрольного елемента.

required (обов'язковий)

Булів атрибут, що показує, що повинен бути обраний варіант із непустим значенням-рядком.

size (розмір)

Якщо контрольний елемент поданий у вигляді віконця списку з прокруткою (наприклад, коли вказано multiple), цей атрибут представляє кількість рядів списку, контрі повинні бути видимі водночас. Браузери не зобов'язані показувати елемент вибору як віконце списку з прокруткою. Усталене значення – 0.

Примітка: Згідно зі специфікацією HTML, усталеним значенням size має бути 1; втім, на практиці виявилось, що це ламає певні вебсайти, і що жоден інший браузер так не робить, тому Mozilla вирішила продовжити повертати в Firefox 0 на постійній основі.

Примітки щодо використання

Вибір декількох варіантів

На настільних комп'ютерах доступна низка способів обрати декілька варіантів у елементі <select> з атрибутом multiple:

Користувачі миші можуть утримувати клавішу Ctrl, Command чи Shift (залежно від того, що має зміст для вашої операційної системи), а потім клацнути декілька варіантів, щоб обрати їх або скасувати вибір.

Застереження: Механізм вибору декількох несуміжних елементів за допомогою клавіатури, описаний нижче, схоже, наразі працює лише в Firefox.

На macOS комбінації клавіш Ctrl + вгору та Ctrl + вниз конфліктують з усталеними комбінаціями контролю місії та вікон застосунків, тож ці усталені комбінації слід відключити, перш ніж описаний нижче механізм запрацює.

Користувачі клавіатури можуть обрати декілька суміжних елементів наступним чином:

  • Перевести фокус на елемент <select> (на приклад, використовуючи

    Tab

    ).

  • Обрати елемент нагорі чи внизу діапазону, котрий бажають обрати, використовуючи курсорні клавіші

    вгору

    та

    вниз

    , щоб рухатись вгору та вниз по списку варіантів.

  • Утримуючи клавішу

    Shift

    , за допомогою курсорних клавіш

    вгору

    та

    вниз

    , аби збільшити чи зменшити діапазон обраних елементів.

Користувачі клавіатури можуть обрати декілька несуміжних елементів наступним чином:

  • Перевести фокус на елемент <select> (на приклад, використовуючи

    Tab

    ).

  • Утримуючи клавішу

    Ctrl

    , за допомогою курсорних клавіш

    вгору

    та

    вниз

    , змінювати "сфокусований" варіант вибору, тобто той, котрий стане обраним, якщо так вирішить користувач. "Сфокусований" варіант вибору підсвічується пунктирним контуром, – так само як сфокусоване за допомогою клавіатури посилання.

  • Натискаючи клавішу

    пробіл

    , обрати чи скасувати вибір "сфокусованого" варіанту вибору.

Оформлення засобами CSS

Елемент <select> відомий складністю ефективного оформлення засобами CSS. Можна повпливати на певні аспекти, як і в будь-якого елемента, – наприклад, оперуючи рамковою моделлю, використаним шрифтом тощо, а також можна використати властивість appearance, щоб усунути усталений системний вигляд.

Втім, ці властивості не дають сталих результатах на всіх браузерах, тож важко робити речі штибу шикування різних типів елементів форми одне з одним в один стовпець. Внутрішня структура елемента <select> – складна, а також важка для контролю. При потребі отримати повний контроль слід розглянути варіанти використання бібліотеки з добрими можливостями з оформленнями віджетів форми та розгортання власного спадного меню за допомогою несемантичних елементів і JavaScript, а також WAI-ARIA для надання семантики.

Більше інформації про оформлення <select>:

Також дивіться приклад "Власні стилі select" нижче: він показує, що можна спробувати зробити шляхом простого оформлення <select>.

Приклади

Простий select

Наступний приклад створює украй просте спадне меню, другий варіант котрого є усталено обраним.

<!-- Спершу буде обрано друге значення -->
<select name="choice">
  <option value="first">Перше значення</option>
  <option value="second" selected>Друге значення</option>
  <option value="third">Третє значення</option>
</select>

Результат

Select з групуванням варіантів

Наступний приклад створює спадне меню з групуванням за допомогою <optgroup> і <hr>, щоб користувачу було легше зрозуміти вміст цього спадного меню.

<label for="hr-select">Ваша улюблена їжа</label> <br />

<select name="foods" id="hr-select">
  <option value="">Оберіть їжу</option>
  <hr />
  <optgroup label="Фрукти">
    <option value="apple">Яблука</option>
    <option value="banana">Банани</option>
    <option value="cherry">Вишні</option>
    <option value="damson">Сливи</option>
  </optgroup>
  <hr />
  <optgroup label="Овочі">
    <option value="artichoke">Артишоки</option>
    <option value="broccoli">Броколі</option>
    <option value="cabbage">Капуста</option>
  </optgroup>
  <hr />
  <optgroup label="М'ясо">
    <option value="beef">Яловичина</option>
    <option value="chicken">Курка</option>
    <option value="pork">Свинина</option>
  </optgroup>
  <hr />
  <optgroup label="Риба">
    <option value="cod">Тріска</option>
    <option value="haddock">Пікша</option>
    <option value="salmon">Лосось</option>
    <option value="turbot">Калкан</option>
  </optgroup>
</select>

Результат

Поглиблений приклад select з використанням багатьох можливостей

Наступний приклад – складніший, він показує більше можливостей, котрі можна використати з елементом <select>:

<label
  >Будь ласка, оберіть одну чи більше тваринок:
  <select name="pets" multiple size="4">
    <optgroup label="Чотирилапі">
      <option value="dog">Пес</option>
      <option value="cat">Кіт</option>
      <option value="hamster" disabled>Хом'як</option>
    </optgroup>
    <optgroup label="Птахи">
      <option value="parrot">Папуга</option>
      <option value="macaw">Ара</option>
      <option value="albatross">Альбатрос</option>
    </optgroup>
  </select>
</label>

Результат

Ви побачите, що

  • Можна обрати декілька варіантів, адже додано атрибут multiple.
  • Атрибут size приводить до того, що водночас видно лише 4 пункти; щоб побачити усі варіанти, можна використати прокручування.
  • Ми додали елементи <optgroup>, щоб поділити варіанти на різні групи. Це суто візуальне групування, чиє відображення в цілому складається із назви групи грубим шрифтом та відступу на варіантах.
  • Варіант "Хом'як" має атрибут disabled, а тому не може бути обраний узагалі.

Власне оформлення select

Цей приклад показує, як можна було б використати трохи CSS та JavaScript для більш детального власного оформлення рамки <select>.

Сам приклад:

  • Клонує контекст <select> (елементи <option>) в обгортку-предка та наново реалізує стандартну очікувану поведінку за допомогою додаткових елементів HTML та JavaScript. В тому числі базову поведінку табуляції для надання доступності з клавіатури.
  • Відтворює певні стандартні нативні атрибути у вигляді data--атрибутів нових елементів, щоб керувати станом та CSS.

Примітка: Не всі нативні можливості підтримуються; це лишень підтвердження концепції. Реалізація заснована на стандартному HTML, але таких само результатів можна було б досягти на основі JSON-даних, власного HTML чи інших рішень.

HTML

<form>
  <section>
    <label for="select-standard">Стандартні контрольні елементи:</label>
    <select name="1A" id="select-standard">
      <option>Морква</option>
      <option>Горох</option>
      <option>Квасоля</option>
      <option>Дихлордифенілтрихлорметилметан</option>
    </select>
  </section>
  <hr />
  <section id="custom">
    <label for="select-custom">Власні контрольні елементи:</label>
    <select name="2A" id="select-custom">
      <option>Морква</option>
      <option>Горох</option>
      <option>Квасоля</option>
      <option>Дихлордифенілтрихлорметилметан</option>
    </select>
  </section>
</form>

CSS

body {
  font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
  padding: 20px;
}

hr {
  margin: 20px 0;
}

label {
  margin-right: 10px;
}

.select:focus {
  border-color: blue;
}

.select[data-multiple] header {
  display: none;
}

.select div.header {
  content: "↓";
  display: flex;
  flex: 1;
  align-items: center;
  padding: 0;
  position: relative;
  width: auto;
  box-sizing: border-box;
  border-width: 1px;
  border-style: inherit;
  border-color: inherit;
  border-radius: inherit;
}

.select .header::after {
  content: "↓";
  align-self: stretch;
  display: flex;
  align-content: center;
  justify-content: center;
  justify-items: center;
  align-items: center;
  padding: 0.5em;
}

.select .header:hover::after {
  background-color: blue;
}

.select .header select {
  appearance: none;
  font-family: inherit;
  font-size: inherit;
  padding: 0;
  border-width: 0;
  width: 100%;
  flex: 1;
  display: none;
}
.select .header select optgroup {
  display: none;
}
.select select div.option {
  display: none;
}

.select {
  user-select: none;
  box-sizing: border-box;
  position: relative;
  border-radius: 4px;
  border-style: solid;
  border-width: 0;
  border-color: gray;
  width: auto;
  display: inline-block;
}

.select:focus,
.select:hover {
  border-color: blue;
}

.select[data-open] {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.select[data-open] datalist {
  display: initial;
}

.select datalist {
  appearance: none;
  position: absolute;
  border-style: solid;
  border-width: 1px;
  border-color: gray;
  left: 0;
  display: none;
  width: 100%;
  box-sizing: border-box;
  z-index: 2;
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}

.select datalist .option {
  background-color: white;
  margin-bottom: 1px;
  cursor: pointer;
  padding: 0.5em;
  border-width: 0;
}

.select datalist .option:hover,
.select datalist .option:focus,
.select datalist .option:checked {
  background-color: blue;
  color: white;
}

.select .optgroup .option[data-disabled] {
  color: gray;
}

.select .optgroup .option[data-checked] {
  background-color: blue;
  color: white;
}

.select .optgroup .label {
  font-weight: bold;
}

.select .optgroup .option .label {
  font-weight: normal;
  padding: 0.25em;
}

.select .header span {
  flex: 1;
  padding: 0.5em;
}

JavaScript

const selects = custom.querySelectorAll("select");
for (const select of selects) {
  const div = document.createElement("div");
  const header = document.createElement("div");
  const datalist = document.createElement("datalist");
  const optgroups = select.querySelectorAll("optgroup");
  const span = document.createElement("span");
  const options = select.options;
  const parent = select.parentElement;
  const multiple = select.hasAttribute("multiple");
  function onclick(e) {
    const disabled = this.hasAttribute("data-disabled");
    select.value = this.dataset.value;
    span.innerText = this.dataset.label;
    if (disabled) return;
    if (multiple) {
      if (e.shiftKey) {
        const checked = this.hasAttribute("data-checked");
        if (checked) {
          this.removeAttribute("data-checked");
        } else {
          this.setAttribute("data-checked", "");
        }
      } else {
        const options = div.querySelectorAll(".option");
        for (let i = 0; i < options.length; i++) {
          const option = options[i];
          option.removeAttribute("data-checked");
        }
        this.setAttribute("data-checked", "");
      }
    }
  }

  function onkeyup(e) {
    e.preventDefault();
    e.stopPropagation();
    if (e.keyCode === 13) {
      this.click();
    }
  }

  div.classList.add("select");
  header.classList.add("header");
  div.tabIndex = 1;
  select.tabIndex = -1;
  span.innerText = select.label;
  header.appendChild(span);

  for (const attribute of select.attributes) {
    div.dataset[attribute.name] = attribute.value;
  }
  for (let i = 0; i < options.length; i++) {
    const option = document.createElement("div");
    const label = document.createElement("div");
    const o = options[i];
    for (const attribute of o.attributes) {
      option.dataset[attribute.name] = attribute.value;
    }
    option.classList.add("option");
    label.classList.add("label");
    label.innerText = o.label;
    option.dataset.value = o.value;
    option.dataset.label = o.label;
    option.onclick = onclick;
    option.onkeyup = onkeyup;
    option.tabIndex = i + 1;
    option.appendChild(label);
    datalist.appendChild(option);
  }
  div.appendChild(header);
  for (const o of optgroups) {
    const optgroup = document.createElement("div");
    const label = document.createElement("div");
    const options = o.querySelectorAll("option");

    Object.assign(optgroup, o);
    optgroup.classList.add("optgroup");
    label.classList.add("label");
    label.innerText = o.label;
    optgroup.appendChild(label);
    div.appendChild(optgroup);
    for (const o of options) {
      const option = document.createElement("div");
      const label = document.createElement("div");

      for (const attribute of o.attributes) {
        option.dataset[attribute.name] = attribute.value;
      }
      option.classList.add("option");
      label.classList.add("label");
      label.innerText = o.label;
      option.tabIndex = i + 1;
      option.dataset.value = o.value;
      option.dataset.label = o.label;
      option.onclick = onclick;
      option.onkeyup = onkeyup;
      option.tabIndex = i + 1;
      option.appendChild(label);
      optgroup.appendChild(option);
    }
  }

  div.onclick = (e) => {
    e.preventDefault();
  };

  parent.insertBefore(div, select);
  header.appendChild(select);
  div.appendChild(datalist);
  datalist.style.top = `${header.offsetTop + header.offsetHeight}px`;

  div.onclick = (e) => {
    if (!multiple) {
      const open = div.hasAttribute("data-open");
      e.stopPropagation();
      if (open) {
        div.removeAttribute("data-open");
      } else {
        div.setAttribute("data-open", "");
      }
    }
  };

  div.onkeyup = (event) => {
    event.preventDefault();
    if (event.keyCode === 13) {
      div.click();
    }
  };

  document.addEventListener("click", (e) => {
    if (div.hasAttribute("data-open")) {
      div.removeAttribute("data-open");
    }
  });

  const width = Math.max(
    ...Array.from(options).map((e) => {
      span.innerText = e.label;
      return div.offsetWidth;
    }),
  );

  console.log(width);
  div.style.width = `${width}px`;
}
document.forms[0].onsubmit = (e) => {
  const data = new FormData(this);
  e.preventDefault();
  submit.innerText = JSON.stringify([...data.entries()]);
};

Результат

Занепокоєння щодо доступності

Елемент <hr> усередині <select> слід розглядати як суто декоративний, оскільки він наразі не відображається у дереві доступності, а отже – не видається допоміжним технологіям.

Технічний підсумок

Категорії вмісту Потоковий вміст, оповідальний вміст, інтерактивний вміст, перелічений, підписний, скиданий та подавальний асоційований з формою елемент
Дозволений вміст Нуль чи більше елементів <option>, <optgroup> або <hr>.
Пропуск тега Немає; і початковий, і кінцевий теги – обов'язкові.
Дозволені предки Будь-які елементи, котрі приймають оповідальний вміст.
Неявна роль ARIA combobox, якщо немає атрибута multiple і немає атрибута size зі значенням, більшим за 1, інакше – listbox
Дозволені ролі ARIA menu, якщо немає атрибута multiple і немає атрибута size зі значенням, більшим за 1, інакше – всі ролі недозволені
Інтерфейс DOM HTMLSelectElement

Специфікації

Сумісність із браузерами

desktop mobile
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet
select
Chrome Full support Yes
footnote
Edge Full support 12
Firefox Full support 1
footnote
Internet Explorer Full support Yes
Opera Full support Yes
Safari Full support Yes
footnote
WebView Android Full support Yes
footnote
Chrome Android Full support Yes
footnote
Firefox for Android Full support 4
footnote
Opera Android Full support Yes
Safari on iOS Full support Yes
footnote
Samsung Internet Full support Yes
footnote
disabled
Chrome Full support Yes
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support Yes
Opera Full support Yes
Safari Full support Yes
WebView Android Full support Yes
Chrome Android Full support Yes
Firefox for Android Full support 4
Opera Android Full support Yes
Safari on iOS Full support Yes
Samsung Internet Full support Yes
form
Chrome Full support Yes
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support Yes
Opera Full support Yes
Safari Full support Yes
WebView Android Full support Yes
Chrome Android Full support Yes
Firefox for Android Full support 4
Opera Android Full support Yes
Safari on iOS Full support Yes
Samsung Internet Full support Yes
multiple
Chrome Full support Yes
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support Yes
Opera Full support Yes
Safari Full support Yes
WebView Android Full support Yes
Chrome Android Full support Yes
Firefox for Android Full support 4
Opera Android Full support Yes
Safari on iOS Full support Yes
Samsung Internet Full support Yes
name
Chrome Full support Yes
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support Yes
Opera Full support Yes
Safari Full support Yes
WebView Android Full support Yes
Chrome Android Full support Yes
Firefox for Android Full support 4
Opera Android Full support Yes
Safari on iOS Full support Yes
Samsung Internet Full support Yes
required
Chrome Full support Yes
Edge Full support 12
Firefox Full support 4
Internet Explorer Full support 10
Opera Full support Yes
Safari Full support Yes
WebView Android Full support Yes
Chrome Android Full support Yes
Firefox for Android Full support 4
Opera Android Full support Yes
Safari on iOS Full support Yes
Samsung Internet Full support Yes
size
Chrome Full support Yes
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support Yes
Opera Full support Yes
Safari Full support Yes
WebView Android Full support Yes
Chrome Android Full support Yes
Firefox for Android Full support 4
Opera Android Full support Yes
Safari on iOS Full support Yes
Samsung Internet Full support Yes

Дивіться також