Skip to content
RU
Scale
Density
Theme
Accent

Inputs

Inserts

JS Inserting into a field on a press is done by `instrument.js`

A row of inserts for the field beside them: the variables of a template, the keys of an event, the fields of a record. A press puts the value where the caret is.

The component
Markup
<div class="inst-field" style="max-inline-size:30rem">
  <label class="inst-label" for="ins-tpl">Notification template</label>
  <textarea class="inst-textarea inst-u-mono" id="ins-tpl" rows="3">{{name}} has failed
</textarea>
  <div class="inst-inserts">
    <button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="The name of the monitor">{{name}}</button>
    <button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="The address checked">{{target}}</button>
    <button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="The state">{{status}}</button>
    <button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="The text of the error">{{error}}</button>
    <button class="inst-insert" type="button" data-insert-into="#ins-tpl" title="The time of the event">{{time}}</button>
  </div>
</div>

The example is live: put the cursor in the field and press an insert — it lands where the cursor stood rather than at the end.

Contract

What Required Why
A real <button type="button"> yes This is an action. A <span> takes no focus, does not fire on Enter and is not called a button
data-insert-into no Without it the field of the same inst-field is taken. It is wanted when the field lies elsewhere in the markup
Every insert visible at once yes A couple of rows is taken in at a glance. What did not fit and has to be searched for is a reference of the format already, and its place is in documentation rather than under a field

The text of the button is the value — a separate label is not needed. An explanation goes into the title, but it adds to the name rather than replacing it.

A row of ten buttons is traversed by tab, and that is right: each does its own thing. After an insert the focus returns to the field — left on the button, it means the field will have to be found by hand.

The label holds 4.5:1 on a recessed surface in all five themes. The monospaced setting is not decoration here: an insert is an identifier rather than a word, and {{name}} differs from {{node}} character by character.

Variants

There are none. An insert is quieter than an action: there can be a dozen and more of them to one field, and at full voice the palette would shout louder than what the page was opened for. If an insert matters more than the text under it, it is not an insert.

JS

Include the module once per page.

<script type="module" src="instrument.js"></script>

What instrument.js does

It puts the value into the field where the caret is rather than at the end: the cursor is placed where the insert is wanted, and that is where it is expected. A selection is replaced. After an insert the focus returns to the field — otherwise there is nowhere to type the next letter.

The value is taken from data-insert, and without one from the text of the button.

Events

inst:insert bubbles from the button, and its detail is { text, field }. Cancelling leaves the field untouched: an application may want a logic of insertion of its own, with a check of the position, for instance.

form.addEventListener('inst:insert', (e) => {
  if (!allowed.has(e.detail.text)) e.preventDefault();
});

The field itself sends a native input after an insert — frameworks see the change with not one line of glue.

Options

Attribute What it does
data-insert-into The selector of the field. Without it the first textarea/input of the same .inst-field is taken
data-insert What to insert, when it is not the text of the button itself: a short label, a long value

API

Classes
NameWhat it does
class
inst-insertsA row of inserts
inst-insertOne insert. A real <button>
Attributes
NameValueWhat it does
attribute
data-insert-into—The selector of the field to put the value into. Without it the field of the same inst-field is taken
data-insert—What to insert, when it is not the text of the button itself
event
inst:insert—An insert was pressed. detail is { text, field }. Cancelling leaves the field untouched
Tokens
NameValueWhere from
token
--control-h-sm24pxbase +14: density · scale
--surface-sunkenlight-dark(var(--n-2), var(--n-14))base +1: theme
--border-subtlelight-dark(oklch(0 0 0 / 0.07), oklch(1 0 0 / 0.06))one across every cell
--font-monoui-monospace, " , " , " , Consolas, " , monospaceone across every cell
--text-xs0.78125rembase +4: scale
--space-24pxone across every cell
--space-36pxone across every cell
--radius-sm6pxbase +4: scale

Why the kit works this way — the constitution · Open source under MIT, github.com/keshon/instrument