Текстовые поля
Текстовое поле принимает короткое значение в одну строку: имя, адрес почты, пароль или поисковый запрос. Для текста с переносами строк берите многострочное поле, для числа с шагом — поле количества.
Пример
Разметка
Минимальную разметку показывает пример выше. Части вложены так:
label.sf-input → подпись sf-input-label, рамка sf-input-field с
нативным <input> и подсказка sf-input-hint-text-wrap. Поле со знаком
«?» в подписи устроено иначе — см. Поле с пояснением к подписи.
- Оболочка —
<label class="sf-input">с классом размера, классом вида (sf-input--borderedилиsf-input--filled) и утилитамиflex flex-col. Скрипт компонента находит поля поlabel.sf-input. - Подпись —
sf-input-textвнутриsf-input-label. Скрипт связывает её с полем черезaria-labelledby, подсказку — черезaria-describedbyи выдаёт полюid, если его нет. sf-input-fieldрисует рамку и держит всё, что стоит в одной строке с input: значок в начале, текстsf-input-rightв конце, значок подсказки.- Нативный
<input>хранит значение,name, тип,required,readonly,disabled,autocomplete,inputmode,minlength,maxlengthиpattern; браузер проверяет и отправляет его без отдельного кода. - Placeholder показывает пример формата, но не заменяет подпись.
Варианты
Вид
sf-input--bordered отделяет поле тонкой границей — для форм на фоне
страницы. sf-input--filled отделяет его тональной поверхностью — для плотных
форм и панелей. Пока фокус внутри поля с заливкой, оно получает фон
поверхности, как поле с границей. Поведение и состояния у видов одинаковы; в
одной форме держите один вид.
Размер
Три ступени — sf-input--size-1/2, sf-input--size-1 и sf-input--size-2.
Высота поля совпадает с кнопкой той же ступени; размер меняет подпись, текст,
значки и подсказку вместе.
Тип значения
Тип задаёт нативный атрибут type: text, email, password, search,
tel или url. Вместе с autocomplete и inputmode он выбирает клавиатуру
на телефоне и подсказки автозаполнения; вид поля от типа не меняется.
Состав
Подпись обязательна. Звёздочка sf-input-required отмечает обязательное поле
и скрыта от вспомогательных технологий: обязательность передаёт required на
input, а при звёздочке скрипт ставит его сам. Значок sf-icon перед input
поясняет назначение поля, sf-input-right после input — единицу или
сочетание клавиш, sf-icon sf-icon-hint в конце рамки — значок подсказки.
Постоянное пояснение под полем — sf-input-hint-text-wrap.
Маска
data-mask="true" на label.sf-input или на его input включает маску, шаблон
задаёт data-mask-pattern, а полные настройки — JSON в data-mask-options
({"mask": "+{7}(000)000-00-00"}). Настройки input важнее настроек
оболочки, а data-mask-options важнее data-mask-pattern.
Шаблон читается так:
0— цифра,a— буква,*— любой символ;{…}— постоянная часть, которая входит в значение:+{7}показывает+7, и значение без маски начинается с7;\экранирует следующий символ; любой другой символ — постоянная часть, которая только показывается и в значение не входит;[и]принимаются и не учитываются: пока маска ленивая, любая позиция необязательна.
data-mask-lazy="false" показывает весь шаблон сразу, а
data-mask-placeholder-char задаёт символ пустой позиции (_). Числовая
маска — {"mask": "Number"} с настройками scale (знаков после запятой, по
умолчанию 2), radix (по умолчанию ,), thousandsSeparator, signed,
min, max, padFractionalZeros и normalizeZeros: число группируется при
вводе, а при уходе из поля ограничивается пределами и дополняется нулями.
Маска не заменяет подходящий type, нативную и серверную проверку.
Поле с пояснением к подписи
Пояснение к подписи по нажатию — знак «?»
рядом с подписью. Внутри <label> знак стал бы его элементом управления, и
нажатие на подпись открывало бы пояснение вместо перехода в поле. Поэтому у
такого поля оболочка — <div class="sf-input">, подпись — <label for> с
классом sf-input-text, а знак стоит рядом с ней в sf-input-label.
Скрипт поля сам находит только label.sf-input, поэтому оболочку div
связывает вызов SF.Input.setState(оболочка, {}) после sf-loader-ready: он
даёт полю aria-labelledby и aria-describedby к подсказке и с ними же
показывает ошибку. Передавайте ему саму оболочку: элемент внутри div
функция не поднимает до оболочки. Маску и отметку фокуса после щелчка
(sf-input--pointer-focus) такое поле не получает.
Поле с кнопками действий
Кнопки после поля — «Копировать», «Обновить», «Удалить» — стоят с ним в одной
строке и берут ступень поля: у поля sf-input--size-1 кнопки размера 1.
Строка flex flex-wrap items-cross-end gap-1 переносится, а поле с grow basis-60 растёт и начинает с доли строки. Поэтому на телефоне значение
остаётся читаемым, а кнопки, которым не хватило места, уходят под поле;
items-cross-end ставит их по нижнему краю поля, а не подписи.
Состояния
Состояния задают нативные атрибуты input; класс на оболочке нужен только ошибке. Наведение и нажатие компонент показывает сам.
Недоступно
Нативный disabled приглушает рамку, текст и подпись; поле не получает фокус
и не отправляется с формой.
Только чтение
Нативный readonly оставляет поле в порядке фокуса и позволяет выделить и
скопировать значение; оно отправляется с формой. Фон рамки становится
приглушённым.
Ошибка
Класс error на оболочке и на input окрашивает рамку и подсказку цветом
ошибки. Текст ошибки кладите в подсказку с data-field-message="error":
скрипт отметит поле aria-invalid="true" и свяжет сообщение через
aria-errormessage.
Фокус
При переходе клавишей Tab рамка получает кольцо фокуса по :focus-visible.
При нажатии мышью скрипт ставит оболочке sf-input--pointer-focus, и кольцо
не рисуется. В примере фокус показан классом focus-visible на input; смену
заливки на фон поверхности даёт только настоящий фокус.
Доступность
- Видимая подпись обязательна: скрипт связывает её с полем. В компактной
панели без видимой подписи задайте
aria-labelна input. - Значки в рамке декоративные и получают
aria-hidden="true"; смысл передают подпись и подсказка. - Ошибку сообщайте текстом, который объясняет, как исправить значение: одного цвета недостаточно.
- Не кладите внутрь
<label>кнопку, нажатие на которую не должно переводить фокус в поле. - В режиме принудительных цветов кольцо фокуса рисуется системным цветом. Значок в начале и текст в конце стоят по порядку разметки и при письме справа налево меняются местами.
JavaScript
SF.Input.setState(target, state) меняет состояние поля: target — оболочка
label.sf-input или любой элемент внутри неё, а у оболочки div — сама
оболочка. Поля состояния: value, disabled, error (или
invalid) и errorMessage. value меняет и поле с readonly: человек его
не правит, а код может. Текст ошибки скрипт пишет в подсказку и создаёт
её, если подсказки нет; пустая строка очищает подсказку, и прежний текст
подсказки возвращает приложение. После изменения value поле получает
всплывающее событие input.
const field = document.querySelector('input[name="email"]');
SF.Input.setState(field, {invalid: true, errorMessage: 'Укажите рабочую почту'});
Функция возвращает false, если внутри оболочки нет input.
Компонент регистрирует класс Inputs. SF.Loader появляется к событию
sf-loader-init на window; SF.Loader.ready('Inputs', callback) передаёт
класс, когда он зарегистрирован.
const whenLoader = (run) => (window.SF?.Loader ? run() : window.addEventListener('sf-loader-init', run, {once: true}));
whenLoader(() => SF.Loader.ready('Inputs', (Inputs) => {
const field = new Inputs({
param: {label: 'Рабочая почта', name: 'email', inputType: 'email', autocomplete: 'email', required: false, placeholder: '', leftIcon: 'mail'},
});
document.querySelector('#form').append(field.render());
}));
Параметры: label, name, value, placeholder, hint, size (1/2, 1,
2), type (bordered или filled), inputType, required, disabled,
readonly, error (или invalid) с errorMessage, autocomplete,
inputMode, minLength, maxLength, pattern, leftIcon, rightText,
hintIcon, mask с maskPattern или maskOptions. Класс по умолчанию делает
поле обязательным и ставит подпись Label и placeholder placeholder:
задавайте label, required и placeholder явно.
Классы
| Что | Классы |
|---|---|
| Блок | sf-input |
| Части | sf-input-field, sf-input-hint, sf-input-hint-text-wrap, sf-input-label, sf-input-left, sf-input-required, sf-input-right, sf-input-text |
| Модификаторы | sf-input--bordered, sf-input--filled, sf-input--pointer-focus |
| Размеры | sf-input--size-1, sf-input--size-1/2, sf-input--size-2 |
Классы и переменные собраны из CSS выпуска и обновляются вместе с ним.
Переменные
Настройка
Эти переменные — поверхность настройки компонента. Их имена стабильны: переименовать или убрать такую переменную можно только через журнал изменений, с предупреждением, как атрибут. Framework их не задаёт, поэтому значение можно поставить на сам компонент (.sf-input) или на любого предка. Переменные действуют на спокойный вид; наведение, фокус, нажатие, недоступность и ошибка рисуются поверх, поэтому состояния остаются видны.
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
--sf-input-background-color |
Заливка поля в спокойном состоянии; у фокуса, ошибки и недоступности своя. | var(--sf-surface-0); зависит от вида |
--sf-input-border-color |
Рамка поля в спокойном состоянии. | var(--sf-outline); зависит от вида |
--sf-input-color |
Цвет введённого текста. | inherit |
--sf-input-radius |
Скругление углов поля. | var(--sf-radius--ui) |
--sf-input-padding-inline |
Внутренний отступ поля до и после содержимого по строчной оси. | var(--sf-ui-1--space-x); зависит от размера |
--sf-input-padding-block |
Внутренний отступ поля над и под содержимым. | calc(var(--sf-ui-1--space-y-tightness-default) - var(--sf-px)); зависит от размера |
.sf-input {
--sf-input-radius: 0;
}
Устройство
Остальные переменные — внутренняя проводка компонента: модификаторы задают им значения, а части их читают. Их имена и устройство могут меняться в любом выпуске, поэтому проект их не задаёт. Значение по умолчанию — из базового правила блока (.sf-input); переменную без него задают только модификаторы.
| Переменная | По умолчанию | Задаёт |
|---|---|---|
--sf-input--radius |
var(--sf-input-radius, var(--sf-radius--ui)) |
--sf-input-field--border-end-end-radius, --sf-input-field--border-end-start-radius, --sf-input-field--border-start-end-radius, --sf-input-field--border-start-start-radius |
--sf-input-field--background-color |
не задана; задают модификаторы, например .sf-input.error.sf-input--bordered .sf-input-field: var(--sf-transparent-for-focus) |
background-color |
--sf-input-field--border |
не задана; задают модификаторы, например .sf-input .sf-input-field: var(--sf-px) solid |
border, border-color, border-end-end-radius, border-end-start-radius, border-start-end-radius, border-start-start-radius |
--sf-input-field--border-color |
не задана; задают модификаторы, например .sf-input.error.sf-input--bordered .sf-input-field: var(--sf-error) |
border-color |
--sf-input-field--border-end-end-radius |
не задана; задают модификаторы, например .sf-input .sf-input-field: var(--sf-input--radius) |
border-end-end-radius |
--sf-input-field--border-end-start-radius |
не задана; задают модификаторы, например .sf-input .sf-input-field: var(--sf-input--radius) |
border-end-start-radius |
--sf-input-field--border-start-end-radius |
не задана; задают модификаторы, например .sf-input .sf-input-field: var(--sf-input--radius) |
border-start-end-radius |
--sf-input-field--border-start-start-radius |
не задана; задают модификаторы, например .sf-input .sf-input-field: var(--sf-input--radius) |
border-start-start-radius |
--sf-input-field--box-shadow |
не задана; задают модификаторы, например .sf-input:not(.sf-input--pointer-focus)[:has(input:not(:disabled):not(.disabled).focus-visible)] .sf-input-field: none |
box-shadow |
--sf-input-field--padding-bottom |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field: var(--sf-input-padding-block, calc(var(--sf-ui-1--space-y-tightness-default) - var(--sf-px))) |
padding-bottom |
--sf-input-field--padding-inline-end |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field: var(--sf-input-padding-inline, var(--sf-ui-1--space-x)) |
padding-inline-end |
--sf-input-field--padding-inline-start |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field: var(--sf-input-padding-inline, var(--sf-ui-1--space-x)) |
padding-inline-start |
--sf-input-field--padding-top |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field: var(--sf-input-padding-block, calc(var(--sf-ui-1--space-y-tightness-default) - var(--sf-px))) |
padding-top |
--sf-input-hint--background-color |
не задана; задают модификаторы, например .sf-input .sf-input-hint: transparent |
background-color |
--sf-input-hint-text-wrap--background-color |
не задана; задают модификаторы, например .sf-input .sf-input-hint-text-wrap: transparent |
background-color |
--sf-input-hint-text-wrap--color |
не задана; задают модификаторы, например .sf-input.sf-input--bordered .sf-input-hint-text-wrap: var(--sf-on-surface-variant) |
color |
--sf-input-hint-text-wrap--font-family |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-hint-text-wrap: var(--sf-text--family) |
font-family |
--sf-input-hint-text-wrap--font-size |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-hint-text-wrap: var(--sf-text-size-1/2) |
font-size |
--sf-input-hint-text-wrap--font-weight |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-hint-text-wrap: var(--sf-font-weight-regular) |
font-weight |
--sf-input-hint-text-wrap--line-height |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-hint-text-wrap: var(--sf-text-height-1/2) |
line-height |
--sf-input-input--background-color |
не задана; задают модификаторы, например .sf-input .sf-input-field input: transparent |
background-color |
--sf-input-input--color |
не задана; задают модификаторы, например .sf-input.sf-input--bordered input: var(--sf-on-surface) |
color |
--sf-input-input--font-family |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 input: var(--sf-text--family) |
font-family |
--sf-input-input--font-size |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 input: var(--sf-text-size-1) |
font-size |
--sf-input-input--line-height |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 input: var(--sf-text-height-1) |
line-height |
--sf-input-input--padding-inline-end |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field input: var(--sf-ui-1--text-space-x) |
padding-inline-end |
--sf-input-input--padding-inline-start |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field input: var(--sf-ui-1--text-space-x) |
padding-inline-start |
--sf-input-label--background-color |
не задана; задают модификаторы, например .sf-input .sf-input-label: transparent |
background-color |
--sf-input-label--gap |
не задана; задают модификаторы, например .sf-input .sf-input-label: var(--sf-space-1/4) |
gap |
--sf-input-left--background-color |
не задана; задают модификаторы, например .sf-input .sf-input-left: transparent |
background-color |
--sf-input-placeholder--color |
не задана; задают модификаторы, например .sf-input .sf-input-field input::-webkit-input-placeholder: var(--sf-on-surface-variant) |
color |
--sf-input-placeholder--font-family |
не задана; задают модификаторы, например .sf-input .sf-input-field input::-webkit-input-placeholder: var(--sf-text--family) |
font-family |
--sf-input-placeholder--font-size |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field input::-webkit-input-placeholder: var(--sf-text-size-1) |
font-size |
--sf-input-placeholder--line-height |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field input::-webkit-input-placeholder: var(--sf-text-height-1) |
line-height |
--sf-input-required--color |
не задана; задают модификаторы, например .sf-input .sf-input-required: var(--sf-error) |
color |
--sf-input-required--font-family |
не задана; задают модификаторы, например .sf-input .sf-input-required: var(--sf-text--family) |
font-family |
--sf-input-required--font-size |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-required: var(--sf-text-size-1/2) |
font-size |
--sf-input-required--font-weight |
не задана; задают модификаторы, например .sf-input .sf-input-required: var(--sf-font-weight-regular) |
font-weight |
--sf-input-required--line-height |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-required: var(--sf-text-height-1/2) |
line-height |
--sf-input-right--background-color |
не задана; задают модификаторы, например .sf-input .sf-input-right: transparent |
background-color |
--sf-input-right--padding-inline-end |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-right: var(--sf-ui-1--text-space-x) |
padding-inline-end |
--sf-input-right--padding-inline-start |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-right: var(--sf-ui-1--text-space-x) |
padding-inline-start |
--sf-input-text--color |
не задана; задают модификаторы, например .sf-input .sf-input-text: var(--sf-on-surface-variant) |
color |
--sf-input-text--font-family |
не задана; задают модификаторы, например .sf-input .sf-input-text: var(--sf-text--family) |
font-family |
--sf-input-text--font-size |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field .sf-input-right .sf-input-text: var(--sf-text-size-1) |
font-size |
--sf-input-text--font-weight |
не задана; задают модификаторы, например .sf-input .sf-input-text: var(--sf-font-weight-regular) |
font-weight |
--sf-input-text--line-height |
не задана; задают модификаторы, например .sf-input.sf-input--size-1 .sf-input-field .sf-input-right .sf-input-text: var(--sf-text-height-1) |
line-height |