Тег <input> — самый многоликий в HTML. Один и тот же пустой элемент без закрывающего тега умеет быть строкой для имени, календарём, ползунком громкости, палитрой, кнопкой загрузки файла и даже невидимым полем. Всё решает один атрибут — type. Значений у него больше двадцати, и новички обычно ограничиваются text, а остальное дописывают на JavaScript.
Ниже — все типы, сгруппированные по задаче, которую они решают, с подвохами каждого. А в конце — шпаргалка по атрибутам: какой из них с каким типом вообще работает.
Что на самом деле меняет type
Смена type — это не косметика. Браузер получает подсказку сразу в четырёх местах:
- клавиатура на телефоне — для email появится кнопка @, для tel — цифровая панель;
- встроенная проверка — форма не отправится, пока значение не подходит под тип;
- виджет — календарь, палитра, ползунок, окно выбора файла;
- формат значения — например, дата всегда приходит в виде 2026-03-14, как бы она ни выглядела на экране.
Если браузер не знает указанный тип, он молча превращает поле в обычное текстовое. Поэтому новые типы безопасно ставить сразу: в худшем случае пользователь получит привычную строку ввода.
<label for="nickname">Никнейм</label>
<input type="text" id="nickname" name="nickname">
<!-- опечатка в типе — браузер покажет обычное text-поле -->
<input type="emial" name="contact">
Атрибут for у подписи должен совпадать с id поля, иначе клик по тексту не поставит фокус в поле, а скринридер не прочитает подпись. Ошибка банальная, но встречается даже в учебных примерах. Почему подпись нельзя заменить подсказкой внутри поля — в статье placeholder — это не label.
Текстовые поля, которые умнее text
Все эти типы выглядят как одна строка ввода, но ведут себя по-разному.
<input type="email" name="email" multiple>
<input type="url" name="site" placeholder="https://example.com">
<input type="tel" name="phone" pattern="\+?[0-9 \(\)\-]{7,20}">
<input type="search" name="q">
<input type="password" name="password" minlength="8">
- email проверяет, что в строке есть @ и что-то до и после неё. С атрибутом multiple принимает несколько адресов через запятую.
- url требует абсолютный адрес со схемой: example.com не пройдёт, https://example.com пройдёт. Если нужен строго https, добавьте pattern="https://.*". Как проверять адреса уже в коде — в статье про валидацию URL в JavaScript.
- tel ничего не проверяет: форматы номеров в разных странах слишком разные. Он только открывает цифровую клавиатуру, а правило задаёт pattern.
- search — то же текстовое поле, но браузер знает, что это поиск: в Chromium и Safari появляется крестик очистки, а на мобильных клавиша ввода превращается в «Найти».
- password прячет символы за точками. Менеджеры паролей опознают поле именно по этому типу, а с правильным autocomplete браузер ещё и предложит сгенерировать надёжный пароль — подробно в статье про формы логина и регистрации.
number: значение всё равно строка
type="number" пропускает только число, рисует стрелки-счётчики и понимает min, max и step. Но свойство value в JavaScript всё равно возвращает строку. Число берут из valueAsNumber; у пустого поля там будет NaN.
<input type="number" id="qty" name="qty" min="1" max="99" step="1" value="2">
const qty = document.querySelector('#qty');
qty.value + 1; // '21' — склейка строк
qty.valueAsNumber + 1; // 3
Номер карты, PIN-код, код из СМС, почтовый индекс и номер телефона через number не делают. Это не числа, а наборы цифр: при переводе в число пропадёт ведущий ноль, стрелки на клавиатуре прибавят к PIN единицу, а в поле можно вписать букву e — для браузера это часть экспоненциальной записи числа. Для таких полей берут type="text" с inputmode="numeric" — цифровая клавиатура будет, а лишнего поведения нет. Про inputmode подробнее — в подборке недооценённых HTML-атрибутов.
<input type="text" name="otp" inputmode="numeric" pattern="[0-9]{6}" autocomplete="one-time-code">
Дата и время
Пять типов открывают системный выбор даты или времени. Пользователь видит формат своей локали (например, 14.03.2026), а в value и на сервер всегда уходит машиночитаемая строка:
| Тип | Что выбирают | Формат value |
| date | день, месяц, год | 2026-03-14 |
| time | часы и минуты | 09:30 |
| datetime-local | дату и время, без часового пояса | 2026-03-14T09:30 |
| month | месяц и год | 2026-03 |
| week | неделю и год | 2026-W11 |
Границы задают min и max в том же формате, что и значение. step у date считается в днях, у time — в секундах: step="900" оставит только слоты по 15 минут, а шаг меньше 60 добавит в поле секунды.
<label for="checkin">Заезд</label>
<input type="date" id="checkin" name="checkin" min="2026-03-01" max="2026-12-31">
<label for="slot">Время звонка</label>
<input type="time" id="slot" name="slot" min="09:00" max="18:00" step="900">
Слова «без часового пояса» у datetime-local важны: 09:30 из Киева и 09:30 из Варшавы придут на сервер одинаковыми. Если момент времени должен быть абсолютным, пояс пользователя передают отдельно.
date и time сегодня работают везде:
С datetime-local история длиннее. Сам тип давно поддерживается, но Firefox до версии 154 показывал для него только календарь, а время приходилось вбивать руками. Выбор времени там появился вместе с починкой type="time" (bug 1726107). Safari по-прежнему показывает календарь без выбора времени, и это сознательное решение команды WebKit.
С month и week хуже всего: в Firefox и десктопном Safari они остаются простыми текстовыми полями, без календаря и без проверки формата. Если без выбора недели не обойтись, нужен запасной вариант — два <select> или JS-календарь.
Выбор из вариантов
checkbox и radio
Флажок — независимое «да/нет»: можно отметить сколько угодно. Переключатели объединяются в группу одинаковым name, и отмеченным в группе может быть только один. Атрибут checked отмечает вариант при загрузке и работает только у этих двух типов.
<fieldset>
<legend>Доставка</legend>
<label><input type="radio" name="delivery" value="courier" checked> Курьер</label>
<label><input type="radio" name="delivery" value="pickup"> Самовывоз</label>
</fieldset>
<label><input type="checkbox" name="gift" value="yes"> Упаковать как подарок</label>
Неотмеченный флажок в данные формы не попадает вовсе — сервер не получит ни gift=no, ни пустую строку. А отмеченный без атрибута value отправит gift=on. Группу переключателей удобно оборачивать в <fieldset>: <legend> станет общей подписью для скринридера. Как оформить такую рамку — в статье про fieldset и legend.
У флажка есть свежий атрибут switch: он рисует системный переключатель вместо квадратика. Пока это предложение в WHATWG, а не часть спецификации, и поддерживает его только Safari. Остальные браузеры атрибут игнорируют и показывают обычный флажок, так что ничего не сломается.
<label><input type="checkbox" name="dark" switch> Тёмная тема</label>
range: ползунок
Подходит, когда точное значение не так важно, как примерное: громкость, яркость, «насколько вам понравилось». По умолчанию диапазон от 0 до 100 с шагом 1, а начальное значение стоит посередине. Сам ползунок число не показывает, поэтому его выводят рядом через <output>.
<label for="volume">Громкость</label>
<input type="range" id="volume" name="volume" min="0" max="10" step="1" value="4">
<output for="volume" id="volume-value">4</output>
const volume = document.querySelector('#volume');
const volumeValue = document.querySelector('#volume-value');
volume.addEventListener('input', () => {
volumeValue.value = volume.value;
});
color: палитра
Открывает системный выбор цвета. Значение всегда приходит семисимвольным hex в нижнем регистре, вроде #3a7bd5, а у пустого поля по умолчанию стоит #000000. Названия цветов и короткая запись вида #fff в value не принимаются.
<label for="accent">Цвет акцента</label>
<input type="color" id="accent" name="accent" value="#3a7bd5">
В спецификацию недавно добавили атрибуты alpha (выбор прозрачности) и colorspace="display-p3" (широкий цветовой охват). Пока их поддерживает только Safari начиная с 18.4, поэтому в рабочих формах на них рассчитывать рано.
file: загрузка файлов
Рисует кнопку, которая открывает системный диалог выбора файла. accept сужает выбор по MIME-типу или расширению, multiple разрешает выбрать несколько файлов сразу. Чтобы файл ушёл на сервер, у формы должно быть method="post" и enctype="multipart/form-data".
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="photos">Фото товара</label>
<input type="file" id="photos" name="photos" accept="image/png, image/jpeg, .webp" multiple>
<button>Загрузить</button>
</form>
accept — только фильтр в диалоге, а не проверка: пользователь может переключить его на «Все файлы». Тип и размер файла всё равно проверяют на сервере. В JavaScript выбранные файлы лежат в свойстве files, а value из соображений приватности возвращает поддельный путь C:\fakepath\имя-файла. Как показать превью картинки до отправки — в статье про предпросмотр перед загрузкой, а атрибут capture для камеры телефона разобран в подборке атрибутов.
Подсказки через datalist
Ни в одном типе нет готового автодополнения, но его даёт атрибут list. Он связывает поле с <datalist>, и браузер показывает варианты по мере ввода. В отличие от <select>, вписать своё значение тоже можно.
<label for="city">Город</label>
<input type="text" id="city" name="city" list="cities">
<datalist id="cities">
<option value="Kyiv">
<option value="Lviv">
<option value="Warsaw">
<option value="Berlin">
</datalist>
Firefox поддерживает <datalist> частично: у полей даты и времени подсказок там не будет.
Кнопки и служебные поля
Четыре типа превращают <input> в кнопку:
- submit — отправляет форму, текст кнопки берётся из value;
- reset — возвращает все поля к исходным значениям. В реальных формах его ставят редко: случайный клик стирает всё введённое;
- button — кнопка без собственного поведения, только для JavaScript;
- image — картинка, работающая как submit. Нужны src и alt, а размер задают width и height. Вместе с формой она отправляет координаты клика: name.x и name.y.
В новом коде вместо этих типов обычно пишут элемент <button>: внутри него можно разместить иконку и любую разметку, а не только текст из value. Ведёт себя он так же, но учтите, что <button> внутри формы по умолчанию имеет type="submit".
У кнопок отправки (и <input>, и <button>) есть атрибуты, которые переопределяют настройки самой формы только для этой кнопки: formaction, formmethod, formenctype, formtarget и formnovalidate. Классический сценарий — «Опубликовать» и «Сохранить черновик» в одной форме, причём черновик можно сохранить, не заполнив обязательные поля:
<form action="/posts" method="post">
<input type="text" name="title" required>
<textarea name="body" required></textarea>
<input type="submit" value="Опубликовать">
<input type="submit" value="Сохранить черновик" formaction="/drafts" formnovalidate>
</form>
hidden — невидимое, но не секретное
type="hidden" отправляет значение вместе с формой, но не показывает поле на странице. Типичное применение — CSRF-токен или id редактируемой записи.
<input type="hidden" name="order_id" value="5462">
«Скрытое» здесь значит «не нарисованное», а не «защищённое». Значение видно в исходнике страницы и в DevTools, и его можно поменять перед отправкой. Пароли, цены и права доступа в hidden-поля не кладут, а всё, что пришло из них, сервер перепроверяет.
Шпаргалка по атрибутам
Атрибуты <input> работают не со всеми типами: min у текстового поля или maxlength у даты браузер просто проигнорирует. Ниже — что к чему подходит.
| Атрибут | Что делает | С какими типами |
| name, value | ключ и значение в отправленных данных | все (у кнопок value — ещё и текст) |
| required | без значения форма не отправится | все, кроме range, color, hidden и кнопок |
| disabled | поле недоступно и не отправляется | все |
| readonly | менять нельзя, но значение отправляется | текстовые, number, даты |
| placeholder | серая подсказка до ввода | text, search, email, url, tel, password, number |
| minlength, maxlength | длина строки в символах | text, search, email, url, tel, password |
| pattern | регулярное выражение для всего значения | те же шесть текстовых типов |
| size | видимая ширина поля в символах | те же шесть текстовых типов |
| min, max, step | границы и шаг значения | number, range, все пять типов даты и времени |
| multiple | несколько значений в одном поле | email, file |
| accept | фильтр типов файлов в диалоге | file |
| checked | отмечен при загрузке | checkbox, radio |
| list | связь с <datalist> | все, кроме password, checkbox, radio, file, hidden и кнопок |
| autocomplete | подсказка для автозаполнения браузера | текстовые, number, даты, range, color, hidden |
| autofocus | фокус в поле при загрузке страницы | все |
| dirname | вместе со значением отправляет направление текста (ltr/rtl) | текстовые поля, в первую очередь text и search |
| src, alt, width, height | картинка и её размер | image |
Несколько уточнений к таблице. pattern проверяет значение целиком, как будто выражение уже обёрнуто в ^(?:…)$, поэтому якоря дописывать не нужно. Ещё одна ловушка: современные браузеры компилируют pattern с флагом v, а в этом режиме символы ( ) [ ] { } / - | \ внутри квадратных скобок нужно экранировать. Выражение [0-9 ()-] браузер сочтёт ошибочным и молча отключит проверку, а [0-9 \(\)\-] сработает. autofocus ставят максимум на одно поле на странице, и только если пользователь пришёл именно заполнять форму: прыжок фокуса сбивает тех, кто ходит с клавиатуры и скринридером. Как оформить состояние «поле заполнено неверно» без JavaScript, через :user-invalid, — в статье про современные псевдоклассы.
Что уходит на сервер, а что нет
Самая частая причина фразы «поле не отправляется» — правила формирования данных формы, а не баг:
- Поле без name не отправляется совсем, даже если в нём есть id и значение. Сервер узнаёт поля только по name.
- disabled исключает поле из отправки. Нужно показать значение, запретить его править и при этом отправить — берите readonly.
- Неотмеченные checkbox и radio не отправляются.
- Нажатая кнопка отправляет свою пару name=value, только если у неё есть name. Остальные кнопки формы ничего не добавляют.
<form>
<input type="text" value="уйдёт?"> <!-- нет: без name -->
<input type="text" name="sku" value="A-17" disabled> <!-- нет: disabled -->
<input type="text" name="price" value="49" readonly> <!-- да: price=49 -->
<input type="checkbox" name="gift"> <!-- нет: не отмечен -->
<input type="hidden" name="currency" value="EUR"> <!-- да: currency=EUR -->
<button name="action" value="buy">Купить</button> <!-- да, если нажата -->
</form>
И последнее: встроенная проверка через type, required и pattern нужна для удобства пользователя, а не для безопасности. Её отключают одним атрибутом в DevTools или обходят прямым запросом, поэтому сервер проверяет всё заново.
Итог
- Начинайте с подходящего type: клавиатура, проверка и виджет достанутся бесплатно, а неизвестный тип в худшем случае станет текстовым полем.
- number — для величин, с которыми считают. Наборы цифр вроде PIN и номера карты — это text с inputmode="numeric".
- Значения дат всегда в ISO-формате, независимо от того, что видит пользователь. month и week пока без запасного варианта не обходятся.
- Без name поле не отправится, disabled тоже, а readonly — отправится.
- Всё, что проверил браузер, сервер проверяет ещё раз.
Комментарии (0)