Ввод
Вставки
Ряд подстановок для поля рядом: переменные шаблона, ключи события, поля записи. Нажатие кладёт значение на место каретки.
Разметка
<div class="inst-field" style="max-inline-size:30rem">
<label class="inst-label" for="ins-tpl">Шаблон уведомления</label>
<textarea class="inst-textarea inst-u-mono" id="ins-tpl" rows="3">Упал {{name}}
</textarea>
<div class="inst-inserts">
<button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="Имя монитора">{{name}}</button>
<button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="Адрес проверки">{{target}}</button>
<button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="Состояние">{{status}}</button>
<button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="Текст ошибки">{{error}}</button>
<button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="Время события">{{time}}</button>
</div>
</div>
Пример живой: поставьте курсор в поле и нажмите подстановку — она встанет туда, где стоял курсор, а не в конец.
Использование
<div class="inst-field">
<label class="inst-label" for="tpl">Шаблон</label>
<textarea class="inst-textarea" id="tpl"></textarea>
<div class="inst-inserts">
<button class="inst-insert" type="button" data-insert-into="#tpl">{{name}}</button>
</div>
</div>
| Что | Обязательно | Почему |
|---|---|---|
Настоящая <button type="button"> |
да | Это действие. <span> не получит фокус, не сработает по Enter и не назовётся кнопкой |
data-insert-into |
нет | Без него берётся поле того же inst-field. Указывать нужно, когда поле лежит в другом месте разметки |
| Все подстановки видны разом | да | Пара рядов читается взглядом. То, что не поместилось и требует поиска, — уже справочник формата, и ему место в документации, а не под полем |
Когда использовать
| Используйте | Возьмите другое |
|---|---|
| Подстановка в текст, который человек пишет сам | Выбор одного значения — селект: у подстановок нет выбранного состояния |
| Ключи шаблона, поля записи, переменные события | Метка, которую снимают — тег |
| Палитра под полем ввода | Состояние объекта — бейдж: он сообщает, а не действует |
Варианты
Вариантов нет намеренно. Подстановка тише действия: их бывает по десятку и больше на одно поле, и в полный голос палитра кричала бы громче того, ради чего страница открыта. Если подстановка важнее текста под ней — это не подстановка.
JS
Подключите модуль один раз на страницу.
<script type="module" src="src/kit.js"></script>
Что делает кит
Кладёт значение в поле на место каретки, а не в конец: курсор ставят туда, где нужна подстановка, и ждут её там. Выделенное заменяется. После вставки фокус возвращается в поле — иначе следующую букву некуда набрать.
Значение берётся из data-insert, а без него — из текста кнопки.
События
inst:insert всплывает с кнопки, detail — { text, field }. Отмена
оставляет поле нетронутым: приложению может понадобиться своя логика вставки,
например с проверкой позиции.
form.addEventListener('inst:insert', (e) => {
if (!allowed.has(e.detail.text)) e.preventDefault();
});
Само поле после вставки шлёт нативный input — рамки видят изменение без
единой строки клея.
Опции
| Атрибут | Что делает |
|---|---|
data-insert-into |
Селектор поля. Без него берётся первое textarea/input того же .inst-field |
data-insert |
Что вставить, если это не текст самой кнопки: короткая подпись, длинное значение |
Правила
Так Настоящая кнопка
<button type="button"> внутри формы. Без type она отправит форму при
первом же нажатии.
Не так Подстановка тегом
Тег снимают, и у него есть крестик. Подстановку не снимают — её вставляют.
Так Подпись = то, что вставится
На кнопке написано {{name}}, в поле попадает {{name}}. Расхождение между
надписью и результатом — обман в чистом виде.
Не так Палитра, в которой надо искать
Пока подстановки читаются взглядом, ряд работает. Когда в нём приходится искать глазами — оставьте частые, остальные унесите в документацию формата.
Доступность
| Имя | Текст кнопки и есть значение — отдельная подпись не нужна. Пояснение кладётся в title, но оно дополняет, а не заменяет имя |
| Клавиатура | Обычная кнопка: Tab, Enter, Space. Ряд из десяти кнопок проходится табом, и это правильно — каждая делает своё |
| Фокус после вставки | Возвращается в поле. Оставленный на кнопке фокус означает, что человеку придётся искать поле руками |
| Контраст | Подпись держит 4.5:1 на утопленной поверхности во всех шести темах |
| Моноширинный | Подстановка — идентификатор, а не слово: {{name}} и {{node}} различаются посимвольно |
API
| Имя | Значение | Что делает |
|---|---|---|
| класс | ||
inst-inserts | — | Ряд подстановок |
inst-insert | — | Одна подстановка. Настоящая <button> |
| атрибут | ||
data-insert-into | — | Селектор поля, куда класть значение. Без него берётся поле того же inst-field |
data-insert | — | Что вставить, если это не текст самой кнопки |
| событие | ||
inst:insert | — | Нажата вставка. detail — { text, field }. Отмена оставляет поле нетронутым |
| токен | ||
--control-h-sm | 26px | |
--surface-sunken | light-dark(var(--n-2), var(--n-14)) | |
--border-subtle | light-dark(oklch(0 0 0 / 0.07), oklch(1 0 0 / 0.06)) | |
--font-mono | ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Consolas, "Liberation Mono", monospace | |
--text-xs | 0.75rem | |
--space-2 | 4px | |
--space-3 | 6px | |
--radius-sm | 5px | |
Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument