NumberInput
Числове поле зі степерами, групуванням тисяч і повною клавіатурою — без нативного type=number.
Кількість, ціна, знижка, вага — усе, де число вводять руками, а помилка на порядок коштує грошей.
Стрілки ↑/↓ змінюють на 1, PageUp/PageDown — на 10
Разом: 12 шт., знижка 15 %
Чому не type="number"
Нативне числове поле здається очевидним вибором і не годиться відразу з трьох причин:
- Воно не приймає згрупований рядок. «14 762,50» для нього невалідне значення, тобто групування тисяч вимкнене назавжди.
- Воно малює власні стрілки — поруч із нашими кнопками «−»/«+».
- Для невалідного вводу воно повертає порожній рядок — рівно те саме, що й для порожнього поля. Відрізнити «користувач нічого не ввів» від «користувач ввів казна-що» неможливо.
Тому тут type="text" плюс inputmode="decimal" (числова клавіатура на
телефоні) плюс role="spinbutton" з aria-valuenow/min/max. Роль
обов'язкова: без неї скрінрідер оголошує звичайне текстове поле, і робота
стрілок виглядає як поламка.
Розбір значення розуміє український запис: кому як десятковий роздільник і
нерозривний пробіл як роздільник тисяч. Number.parseFloat на «1 234,5»
повернув би 1.
Видимий рядок — не модель
Клацніть у поле — групування зникне на час редагування
Вкажіть вагу — без неї не порахувати доставку
У фокусі поле показує сире число, поза фокусом — згруповане. Це вимагає тримати видимий рядок окремо від моделі й синхронізувати його з неї лише поки поле не у фокусі.
Інакше відбувається таке: користувач набирає «1,», батько отримує 1,
повертає його назад у поле, рядок перетворюється на «1», а каретка
стрибає в кінець. Проміжні стани — «1,», «-», «0,00» — парсяться в число,
але переписувати рядок на них не можна.
Клавіші ArrowUp/ArrowDown, PageUp/PageDown і Home/End одразу оновлюють і модель, і видимий сирий рядок; після blur рядок знову локалізується.
API
Props
| Назва | Тип | Типово | Опис |
|---|---|---|---|
modelValue | number | null | Значення. Порожнє поле — `null`, ніколи не `NaN`. Через `v-model`. |
size | FieldSize | "md" | Висота поля. На мобільному кожен розмір вищий за десктопний. |
step | number | 1 | Крок стрілок і кнопок «−»/«+». |
precision | number | 0 | Скільки знаків після коми лишати. Округлення відбувається на blur. |
name | string | — | — |
label | string | — | — |
placeholder | string | — | — |
error | string | — | Текст помилки. Стан помилки вмикає САМА наявність тексту. |
hint | string | — | Підказка під полем. Ховається, коли показано помилку. |
id | string | — | — |
min | number | — | Найменше допустиме значення. |
max | number | — | Найбільше допустиме значення. |
stepFast | number | — | Крок PageUp/PageDown. Типово — `step` × 10. |
unit | string | — | Суфікс одиниці: %, грн, шт. Потрапляє і в `aria-valuetext`. |
formatOnBlur | boolean | true | Групувати тисячі, поки поле поза фокусом. У фокусі показується сире число: редагувати рядок із нерозривними пробілами неможливо. |
steppers | boolean | true | Кнопки «−» і «+». Без них лишається чистий числовий ввід. |
required | boolean | — | — |
disabled | boolean | — | — |
readonly | boolean | — | — |
Події
| Назва | Payload | Опис |
|---|---|---|
update:modelValue | [value: number] | Нове значення або `null`, якщо поле порожнє. Використовуйте через `v-model`. |
change | [value: number] | Значення, зафіксоване після втрати фокуса або натискання степерів. |
Доступно через ref
| Назва | Тип | Опис |
|---|---|---|
focus | () => void | Ставить фокус на поле. |
select | () => void | Виділяє весь текст у полі. |
Коли використовувати
- Кількість, ціна, відсоток, вага — будь-яке число з відомим кроком.
- Поля, де стрілки з клавіатури природні: коригування на одиницю.
- Значення з межами, які треба показати користувачу.
Коли НЕ використовувати
- Для номера телефону, картки, рахунку: це не числа, а рядки цифр, і крок
для них не має сенсу. Беріть
UiInput. - Для коду підтвердження —
UiInputOtp. - Для вибору з діапазону, де точне значення не важливе —
UiSlider.
Доступність
role="spinbutton" з aria-valuenow, aria-valuemin, aria-valuemax.
Коли задано unit, значення дублюється в aria-valuetext разом з
одиницею — інакше «15» звучить без «відсотків».
Кнопки «−»/«+» мають tabindex="-1": та сама дія вже доступна стрілками, і
дві зайві зупинки табуляції на кожному числовому полі форми — це дорого.
Розмір кнопок — 44px на мобільному, 36px на десктопі.
Утримання кнопки повторює крок. Таймери знімаються на pointerup,
pointercancel, pointerleave і на приховуванні вкладки: пропустити хоч
один шлях — і значення продовжує рости у фоновій вкладці.